链表的专业术语:

  首节点:存放第一个有效数据的节点
  尾节点:存放最后一个有效数据的节点
  头结点
      1.头结点的数据类型和首节点的数据类型是一模一样的
      2.头结点是首节点前面的那个节点
      3.头结点并不存放有效数据
      4.设置头结点的目的是为了方便对链表的操作
  头指针:存放头结点地址的指针变量

用一张图片来展示链表的基本框架:

⭐尾节点的指针域为空,可以表示为NULL

⭐想要确定一个链表,需要最基本的信息是头指针,之后的信息都可以通过头指针找出来。

接下来编写程序,只有用实际的例子,才能更全面的理解!

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 struct Node                          //定义一个链表结构 
 4 {
 5     int data;                        //链表节点的数据 
 6     struct Node * pNext;             //链表节点指向下一个节点的指针 
 7 };
 8 int i;
 9 struct Node * create_list(void);     //创建链表的函数声明 
10 void traverse_list(struct Node *);   //打印链表的函数声明 
11 int main()
12 {
13     struct Node * pHead = NULL;     //先给头指针赋值为NULL 
14     pHead = create_list();          //调用链表创建函数,并将头指针的值赋给pHead 
15     traverse_list(pHead);           //打印链表
16     return 0;
17 }
18 struct Node * create_list(void)     //创建链表的函数
19 {
20     int len;                        //链表的节点数 
21     int val;                        //链表节点中数据域的值 
22     struct Node * pHead=(struct Node *)malloc(sizeof(struct Node));  //动态分配头结点的内存 
23     if(pHead == NULL)
24     {
25         printf("内存分配失败,程序终止!n");
26         exit(-1);
27     }
28     struct Node * pTail = pHead;                        //定义一个尾节点指针,将pHead的值赋给它 
29     pTail->pNext = NULL;                                //尾节点的指针域一定为空 
30     printf("请输入您需要生成的链表节点的个数:len =");
31     scanf("%d",&len);
32     for (i=0;i<len;i++)
33     {
34         printf("请输入第%d个节点的值:",i+1);
35         scanf("%d",&val);
36         struct Node * pNew=(struct Node *)malloc(sizeof(struct Node));  //动态分配新节点的内存
37         if(pNew== NULL)
38     {
39         printf("内存分配失败,程序终止!n");
40         exit(-1);
41     }
42         pNew->data = val;       //把输入的值传给*pNew数据域 
43         pNew->pNext = NULL;     // *pNew是新的尾节点,所以 pNew->pNext应该为空
44         pTail->pNext = pNew;    //把*pNew的地址传给pTail->pNext指针域,等效于*pTail.pNext=pNew
45                                 //第一次的pTail->pNext = pNew相当于把首节点的地址给了头结点
46                                 
47         pTail = pNew;           48                                 //执行此操作,*pNew就变成了新的*pTail 
49                                 //之后的pTail = pNew则是让最后一个与上一个节点连接上     
50      } 
51     return pHead;               //返回 pHead的值 
52 }
53 void traverse_list(struct Node * pHead)  //遍历链表 
54 {
55     struct Node * p = pHead->pNext;      //定义一个指向下一个节点的指针 
56     while(p!=NULL)                       //尾节点的指针域一定是NULL,如果非NULL,则继续打印 
57     {
58         printf("%dt",p->data);
59         p = p->pNext;                    //下一个节点的地址赋值给p 
60     }
61     return;                              //循环结束 
62 }

在这个程序中,我对44行和47行的代码思考了很久

最开始总觉得有了44行代码 pTail->pNext = pNew ,47行的代码 pTail = pNew 重复了,删去之后,发现不行,下面对两者的区别进行画图解析:

 

 

第1步:*pTail的地址就是pHead,所以pHead指向*pTail,另外,新创建的*pNew还没有赋值。

第2步:将val赋值给*pNew的数据域,NULL赋值给*pNew的指针域,并把*pNew的地址传给*pTail的指针域

第3步:把*pNew的地址赋值给pTail,让*pNew变成新的*pTail

整个过程大致就是如此,理解了,其实也不难,要掌握更多的知识,需要进一步学习数据结构。

内容来源于网络如有侵权请私信删除
你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!