鱼C论坛

 找回密码
 立即注册
查看: 1510|回复: 0

[学习笔记] 链表的基本操作总和

[复制链接]
发表于 2019-9-5 19:59:54 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
对链表的操作有:增,删,改,查,初始化。这些操作书上都有,似乎也可以完全看得懂,但是真正写起代码来还是一卡一卡的,所以自己再重新敲了一遍,也发现了一点点小规律。
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. /*定义结构体链表节点:
  4.         该结构体有两个属性,一个是int类型的数据域data,另一个是这个结构体本身类型的指针next;
  5.         最后给这个结构体定义了一个别名Node,一个指针别名pNode;*/

  6. //节点结构体
  7. struct Node
  8. {
  9.         int data;  //数据域
  10.         struct Node* pNext;  //指针域

  11. };

  12. //头指针和尾指针定义
  13. //为什么要写尾指针呢,方便操作(尾添加)
  14. struct Node* pHead = NULL;
  15. struct Node* pEnd = NULL;

  16. //初始化头结点
  17. void initListHead()
  18. {
  19.         //pHead已经是一个全局变量了
  20.     pHead = (struct Node*)malloc(sizeof(struct Node));
  21.         if (NULL == pHead)
  22.         {
  23.                 printf("内存不足!");
  24.                 exit(0);
  25.         }
  26.         pHead->pNext = NULL;
  27.         pEnd = pHead;
  28. }

  29. //尾添加
  30. void addListEnd(int a)
  31. {
  32.         //创建一个新节点
  33.         struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));
  34.         if (NULL == pTemp)
  35.         {
  36.                 printf("创建节点失败!");
  37.                 exit(0);
  38.         }

  39.         //将新节点赋值
  40.         pTemp->data = a;
  41.         pTemp->pNext = NULL;

  42.         //将新节点链接到链表中
  43.         pEnd->pNext = pTemp;
  44.         pEnd = pTemp;
  45. }

  46. //头添加
  47. void addListHead(int a)
  48. {
  49.         //创建新的节点
  50.         struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));
  51.         if (NULL == pTemp)
  52.         {
  53.                 printf("创建节点失败!");
  54.                 exit(0);
  55.         }

  56.         //将新节点赋值
  57.         pTemp->data = a;
  58.         pTemp->pNext = NULL;

  59.         //链接  先连后断
  60.         //(先让节点的指针指向头指针的下一个,再让头指针指向新的节点)
  61.         pTemp->pNext = pHead->pNext;
  62.         pHead->pNext = pTemp;
  63. }

  64. //遍历链表
  65. void showList()
  66. {
  67.         //遍历链表要写一个中间指针,方便我们的操作,不能直接将头指针后指,也不能将尾指针前指
  68.         struct Node *p = pHead->pNext;
  69.         while (NULL != p)
  70.         {
  71.                 printf("%d ", p->data);
  72.                 p = p->pNext;
  73.         }
  74.         printf("\n");
  75. }


  76. //查询指定元素是否存在,若存在则并返回节点地址
  77. struct Node* SelectNode(int index)
  78. {
  79.         //遍历整个链表
  80.         struct Node *p = pHead->pNext;
  81.         while (NULL != p)
  82.         {
  83.                 if (index == p->data)
  84.                 {
  85.                         return p;
  86.                 }
  87.                 p = p->pNext;
  88.         }
  89.         return NULL;
  90. }

  91. //在任意位置插入元素
  92. //在任意位置添加结点的时候需要注意的是:要判断这个链表是不是空链表,还要判断能不能找到这个位置
  93. void addListRand(int index,int a)
  94. {
  95.         //判断这个链表是不是空链表
  96.         if (pHead->pNext == NULL)
  97.         {
  98.                 printf("此链表为空表!");
  99.         }

  100.         //进行插入
  101.         //找到插入位置所在的地方(可以在外面再写一个函数,专门找到下标位置)
  102.         struct Node *pTemp=SelectNode(index);

  103.         if (NULL == pTemp)
  104.         {
  105.                 //说明没有找到
  106.                 printf("找不到该节点");
  107.                 return;
  108.         }
  109.         else
  110.         {
  111.                 //创建一个新的节点
  112.                 struct Node* pNode = (struct Node*)malloc(sizeof(struct Node));
  113.                 pNode->data = a;
  114.                 //链接(如果我当前要插入的地方刚好是尾巴)
  115.                 if (pTemp == pEnd)
  116.                 {
  117.                         //尾插入
  118.                         addListEnd(a);
  119.                 }
  120.                 else
  121.                 {
  122.                         pNode->pNext = pTemp->pNext;
  123.                         pTemp->pNext = pNode;
  124.                 }
  125.         }
  126. }

  127. //改
  128. void changeList(int index,int a)
  129. {
  130.         //遍历链表
  131.         struct Node*p = (struct Node*)malloc(sizeof(struct Node));
  132.         p = pHead->pNext;
  133.         while (NULL != p)
  134.         {
  135.                 if (index == p->data)
  136.                 {
  137.                         p->data = a;
  138.                 }
  139.                 p = p->pNext;
  140.         }
  141. }

  142. //删除
  143. //删除头
  144. void deleteHead()
  145. {
  146.         //步骤:1先定义一个变量去记住要删掉的节点
  147.         //2.将头结点指向要删除的下一个节点
  148.         //3.将记住的节点释放掉

  149.         //如果链表为空表,那么就没有必要删除了
  150.         if (pHead->pNext == NULL)
  151.         {
  152.                 printf("此链表为空表!");
  153.         }
  154.         //删除 记住
  155.         struct Node*pTemp = pHead->pNext;
  156.         pHead->pNext = pHead->pNext->pNext;
  157.         //释放
  158.         free(pTemp);
  159. }

  160. //删除尾
  161. void deleteEnd()
  162. {
  163.         //如果链表为空表,那么就没有必要删除了
  164.         if (pHead->pNext == NULL)
  165.         {
  166.                 printf("此链表为空表!");
  167.                 return;
  168.         }
  169.         //只有一个节点
  170.         if (pHead->pNext = pEnd)
  171.         {
  172.                 free(pEnd);
  173.                 pHead->pNext = NULL;
  174.                 pHead = pEnd;
  175.         }
  176.         else
  177.         {
  178.                 //不止一个节点
  179.         //找到尾节点的上一个节点
  180.                 struct Node*p = pHead->pNext;

  181.                 while (NULL != p)
  182.                 {
  183.                         if (p->pNext = pEnd)
  184.                         {
  185.                                 break;
  186.                         }
  187.                         p = p->pNext;
  188.                 }
  189.                 //这个时候p就是尾节点的上一个节点
  190.                 //删除
  191.                 free(pEnd);
  192.                 //变新的尾节点
  193.                 p = pEnd;
  194.                 pEnd = NULL;
  195.         }
  196.         
  197. }

  198. //删除任意(删除元素为a的节点)
  199. void deleteRand(int a)
  200. {
  201.         //判断这个链表是否为空
  202.         if (pHead->pNext == NULL)
  203.         {
  204.                 printf("此链表为空表!");
  205.                 return;
  206.         }
  207.         //链表不为空,遍历找到要删除的那个节点的上一个节点
  208.         struct Node*p = pHead->pNext;

  209.         while (NULL != p)
  210.         {
  211.                 if (p->pNext->data==a)
  212.                 {
  213.                         break;
  214.                 }
  215.                 p = p->pNext;
  216.         }
  217.         //这个时候p就是要删除的那一个节点的上一个节点了
  218.         //如果p这个时候已经是尾节点了
  219.         if (p->pNext == pEnd)
  220.         {
  221.                 deleteEnd();
  222.         }
  223.         else
  224.         {
  225.                 //先记住要删除的节点
  226.                 struct Node* pTemp = p->pNext;
  227.                 p->pNext = p->pNext->pNext;
  228.                 free(pTemp);
  229.         }
  230. }

  231. //释放整个链表
  232. void freeList()
  233. {
  234.         //遍历整个链表(注意,删除的时候需要先记住要删除的节点)
  235.         struct Node* pTemp = pHead;
  236.         while (pTemp != NULL)
  237.         {
  238.                 struct Node* pT = pTemp;
  239.                 pTemp = pTemp->pNext;
  240.                 free(pT);
  241.         }
  242.         pHead = NULL;
  243.         pEnd = NULL;
  244. }

  245. int main(void)
  246. {
  247.         //在main函数中一定要对头节点进行初始化!!!!
  248.         //链表空头
  249.         //但是在后面的代码中,我们发现头结点的初始化是经常要写的,所以我们为了方便还是写一个函数专门初始化头结点
  250.         /*struct Node* pHead = (struct Node*)malloc(sizeof(struct Node));
  251.         pHead->pNext = NULL;
  252.         pEnd = pHead;*/
  253.         initListHead();

  254.         //操作
  255.         addListEnd(1);
  256.         addListEnd(2);
  257.         addListEnd(3);
  258.         addListEnd(4);

  259.         addListRand(2, 6);

  260.         changeList(3, 5);
  261.         //deleteHead();

  262.         //deleteEnd();

  263.         showList();

  264.         deleteRand(5);

  265.         showList();

  266.         printf("删除整个链表\n");
  267.         freeList();
  268.         showList();

  269.         system("pause");
  270.         return 0;
  271. }
复制代码
要想真正搞清楚,不会混乱,其实也没有那么难,将大的化小,有时候就清楚明了了。
在上面代码中,定义了头指针和尾指针,那为什么要定义两个指针呢?只定义一个指针不行吗?其实定义两个指针也是为了后面的方便,能够更好的理解。


初始化:在main函数中,一般都是要写对头结点的初始化的。


增:向链表中添加元素...emmm,咋填?
      分解来看,有三种向链表中增加元素的方法:1.头插入 2.尾插入 3.给定位置插入
      注意了:不管是什么方式插入,都有一样的操作:step 1:创建一个新的节点用来存需要插入的数据   step 2:将数据放进新创建的节点中  step 3:链接到链表上去
      特别的,在任意给定位置插入新节点的时候,需要注意能不能找到这个位置。


删:删除要记住了:
      //步骤:1先定义一个变量去记住要删掉的节点
       //2.将头结点指向要删除的下一个节点
       //3.将记住的节点释放掉同样的 ,删除也可以分成三个方法来删除:1.删头  2.删尾  3.任意删
这三种删除方式都有一个必须要判断的是:这个链表是不是空链表(如果是链表,那删除个啥???)
删头:删头的方式很简单,记住之后之间将头指针指向被删节点的下一个节点,然后释放记住的节点。
删尾:删尾相比较于删头复杂了一点点,但是也是很好理解的:要分成只有一个节点的情况和有多个结点的情况。
特别的,有多个结点的情况的删除,要找到尾节点的上一个节点(只有找到了尾节点的上一个节点,才能重定义尾指针)
任意删:任意删除给定位置的节点的时候,同样需要注意这个链表是不是空链表,并且需要判断能不能找到这个要删除的节点,如果找到了,再进行删除。


改:改的操作就很简单了,遍历整一个链表,如果找到了需要修改的位置,直接将该节点的数据域改成需要修改的值就可以了(需要注意的是,要写出找不到需修改节点的情况)


查:与改类似,略


删除整个链表:删除整个链表的时候,需要定义一个新的节点来记住要删除的节点,然后不断的后移,释放。


emmm,总之,还是要自己亲自动手操作才能完全掌握和理解滴~~


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-7 06:55

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表