单链表的头插法建表和尾插法建表

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sjdjdjdjahd/article/details/90049772
链式存储结构:

用一组不一定连续的存储单元存储逻辑上相邻的元素,元素间的逻辑关系是由附加的指针域表示的,由此得到的存储结构称为链式存储结构。

单链表(线性链表)

使用链式存储结构表示每个数据元素 ai 时,除了存储 ai 本身信息之外,还需要一个存储指示其后继元素 ai+1 存储位置的指针。由这两部分组成元素 ai 的存储映像称为 结点。它包括两个域:存储数据元素的域称为数据域,存储直接后继存储地址的域称为指针域。利用这种存储方式表示的线性表称为链表,n个结点链成一个链表,即为线性表的链式存储结构。由于这种链表的每个结点中只包含一个指针域,因此又称为单链表

在这里插入图片描述
在这里插入图片描述
一个单链表可由头指针唯一确定,因此单链表可以用头指针的名字来命名。
链式存储结构如下:

typedef int DataType;   //定义数据类型
typedef struct node     //结点类型定义
{
    DataType data;      //结点的数据域
    struct node * next; //结点的指针域,存储下一个结点的地址
}ListNode;
typedef ListNode * LinkList; //定义一个指针类型

头插法建表

头插法建表是从一个空表开始,重复读入数据,生成新节点,将读入的数据存放到新节点的数据域中,然后将新节点插入到当前链表的表头上,直到读入结束标志为止。

/*
    头插法建表,并返回头指针
*/
LinkList CreateListF(int arr[],int length)
{
    LinkList head;  //声明指向单链表的头指针
    ListNode * p;   //定义一个指向结点的指针变量
    head = NULL;    //置空单链表

    for(int i = 0; i < length; i++)
    {
        p = (ListNode *)malloc(sizeof(ListNode));   //申请一个新的结点
        p->data = arr[i];   //数据域复制
        p->next = head;     //指针域赋值
        head = p;           //头指针指向新的结点
        printf("data=%d p=%p\n",p->data,p);
    }
    return head;
}

尾插法建表

将新节点插入当前链表的表尾上,因此需要增设一个尾指针near,使其始终指向链表的尾节点。

/*
    尾插法建表,并返回头指针
*/
LinkList CreateListR(int arr[],int length){
    LinkList head,rear;
    ListNode *p;
    head = NULL; rear = NULL;   //置空单链表

    for(int i = 0; i < length; i++)
    {
        p = (ListNode *)malloc(sizeof(ListNode));   //申请新节点
        p->data = arr[i];   //数据域赋值
        if (head == NULL) {
            head = p;       //新节点*p插入空表
        }else{
            rear->next = p; //新节点*p插入到非空表的表尾节点*rear之后
        }
        rear = p;   //表尾指针指向新的表尾指针
        printf("data=%d p=%p\n",p->data,p);
    }
    if (rear != NULL) {
        rear->next = NULL;  //终端结点的指针域置空
    }
    return head;
}

主程序代码:

#include <stdio.h>
#include "E:/Dev/C/DataStructure/chapter2/LinkList.c"

void printLink();
int main(){
    int arr[] = {1,2,3};
    LinkList head = NULL;

    printf("头插法\n");
    head = CreateListF(arr,3);
    printf("head= %p\n",head);
    printLink(head);

    printf("尾插法\n");
    head = CreateListR(arr,3);
    printf("head= %p\n",head);
    printLink(head);

    return 0;
}

/*
    打印输出链表
*/
void printLink(LinkList head){
     printf("输出:");
    LinkList temp = head; 
    while(temp != NULL){
        printf("%d ",temp->data);
        temp = temp->next;  
    }
    printf("\n");
}

编译运行,输出结果:
在这里插入图片描述
可以看出头插法输入123,输出321。尾插法输入123,输出123。
头插法新建链表节点的次序和输入时的顺序相反,尾插法新建链表节点次序和输入次序相同。

引入带头节点

为了简化算法,方便操作,在链表开始结点前附加一个结点,称为头结点。如下
在这里插入图片描述
尾插法建立单链表算法可简化:

/*
    尾插法建立带头节点的单链表算法
*/
LinkList CreateListR1(int arr[],int length){
    LinkList head = (ListNode *)malloc(sizeof(ListNode));   //申请头结点
    ListNode *p,*r;
    r = head;       //尾指针出事指向头结点
    for(int i = 0; i < length; i++)
    {
        p = (ListNode *)malloc(sizeof(ListNode));   //申请新节点
        p->data = arr[i];
        r->next = p;    //新节点连接到尾结点之后
        r = p;          //尾结点指向新节点  
        printf("data=%d p=%p\n",p->data,p);  
    }
    r->next = NULL; //终端结点指针域置空
    return head;
}

输出结果

尾插法建立带头结点单链表
data=1 p=0000000000176CF0
data=2 p=0000000000176D10
data=3 p=0000000000176D30
输出:1512480 1 2 3

因为增加了头结点,所以输出也就多了一位。因为头结点没有赋值,所以值是没有意义的。

猜你喜欢

转载自blog.csdn.net/sjdjdjdjahd/article/details/90049772