当前位置:   article > 正文

单项链表(数据结构)_单向链表

单向链表

       

目录

单项链表:

单向链表结点

单项链表的初始化:

单向链表的头插法

 单项链表的打印:

单项链表的尾插法

获取链表上的指定元素

获取链表上指定位置上的元素

删除链表上指定位置的元素

删除链表上指定元素所在的结点

在链表指定位置前插入一个结点

插入一个元素使得整个链表依然保持为升序

销毁链表

总的代码:


 前面学习顺序表的时候,线性表的数据储存结构的特点是逻辑关系上相邻的两个元素在物理位置上也是相邻的,虽然顺序表的查询很快,但是由于时间复杂度问题,增删的效率是比较低的,每一次的增删操作都伴随的大量的移动。

     线性表的链式存储结构(也称之为链表)的特点是逻辑关系上相邻的两个数据元素在物理位置上不一定是相邻的,换言之数据元素在存储器中的位置可以是任意的。为了表示每个数据元素ai与其直接后继 ai+1之间的逻辑关系,对于数据元素ai来说,除了存储其本身的信息外,还需存储一个能够保存直接后继的存储位置的指针,这两部分信息组成数据元素ai的存储映像,我们称之为结点(node)。

        结点包含两个或者三个域:存储数据元素信息的域叫做数据域,存储直接后继存储位置的域叫做指针域,存储直接前驱存储位置的域也叫做指针域

  如果只有一个指针域保存直接后继存储位置,这样的链表我们称之为单向链表。

 为了方便对链表进行插入结点和删除结点的操作,一般地链表中的第一个结点不存储实际的数据元素,该结点我们称之为:头结点

  单向链表头结点中数据域不存储实际数据元素:

单项链表:

        在对单项链表经行访问的时候,需要使用一个结点(头节点),这个指针我们称之为头指针。头指针保存了链表中头节点的存储位置、

单向链表结点

  1. /*
  2. * 单项链表的结点
  3. * */
  4. typedef int ElemType ;
  5. typedef struct LNode{
  6. ElemType data;//数据域
  7. struct LNode *next;//指针域,指向当前结点的直接后继
  8. } LNode,*LinkList;//LinkList 的类型为LNode*

单项链表的初始化:

当链表为空的时候头结点的指针域为空;

初始化一个链表:

1、创建一个头结点,头结点的指针域为空

2、创建一个头指针,头指针指向头结点

  1. /*
  2. * @brief 单项链表的初始化
  3. * @return 返回链表的头指针
  4. * */
  5. LinkList List_Init()
  6. {
  7. LNode *t;
  8. t=(LNode *)malloc(sizeof(LNode));//创建一个头节点
  9. t->next=NULL;
  10. LinkList head;//定义一个头指针
  11. head = t;//头指针指向头节点
  12. return head;
  13. }

单向链表的头插法

1、创建一个新的结点p

2、将新的结点p的next指向头结点的下一个结点

3、头结点的next指向新的结点p

  1. //单项链表的头插法
  2. /*
  3. * @brief 头插法插入一个结点
  4. * @param 需要插入链表的头指针
  5. * @param 需要插入的数据
  6. * return 成功返回TRUE,失败返回FALSE
  7. * */
  8. int Head_Insert(LinkList head,ElemType data)
  9. {
  10. if(NULL==head)
  11. return FALSE;
  12. //创建一个新的结点p
  13. LNode *p=(LNode *)malloc(sizeof(LNode));
  14. p->data=data;
  15. //将新的结点p的next指向头结点的下一个结点(之前的上一个结点)(head->next)
  16. p->next=head->next;
  17. //头结点的next指向新的结点p
  18. head->next=p;
  19. return TRUE;
  20. }

 单项链表的打印:

1、使用一个临时指针指向头结点后的第一个结点

2、使用临时指针进行遍历,直到临时指针为NULL

  1. //单项链表的打印
  2. /*
  3. * @brief 输出链表中的所有结点
  4. * @param head 链表的头指针
  5. * @return 成功返回TRUE ,失败返回FALSE
  6. * */
  7. int Print_List(LinkList head)
  8. {
  9. if(NULL==head)
  10. return FALSE;
  11. //使用一个临时指针对链表进行遍历
  12. LNode *p=head->next;
  13. while(p!=NULL)
  14. {
  15. printf("[%d]",p->data);
  16. p=p->next;
  17. }
  18. return TRUE;
  19. }

单项链表的尾插法

1、新建一个新的结点

2、将为指针的next指向新的结点地址

3、将尾指针指向新的结点

在写尾插法之前先要获取链表的尾指针地址

1、在链表创建完成后遍历一边链表,以获取其尾指针地址

2、在创建链表的同时,确定尾指针地址

显然,第二种方法比第一种简单,所以我们直接修改之前的头插法函数

  1. //单项链表的头插法
  2. /*
  3. * @brief 头插法插入一个结点
  4. * @param head 需要插入链表的头指针
  5. * @param tail 尾结点指针地址
  6. * @param data 需要插入的数据
  7. * return 成功返回TRUE,失败返回FALSE
  8. * */
  9. int Head_Insert(LinkList head,LNode **tail,ElemType data)
  10. {
  11. if(NULL==head)
  12. return FALSE;
  13. //创建一个新的结点p
  14. LNode *p=(LNode *)malloc(sizeof(LNode));
  15. p->data=data;
  16. P->next=NULL;
  17. //如果链表为空,那么插入的结点就是整个链表的尾结点
  18. if(NULL==head->next)
  19. *tail = p;
  20. //将新的结点p的next指向头结点的下一个结点(之前的上一个结点)(head->next)
  21. p->next=head->next;
  22. //头结点的next指向新的结点p
  23. head->next=p;
  24. return TRUE;
  25. }

尾插法代码示例:

  1. //单项链表的尾接法
  2. /*
  3. * @brief 头插法插入一个结点
  4. * @param head 需要插入链表的头指针
  5. * @param tail 尾结点指针的地址
  6. * @param date 需要插入的数据
  7. * return 成功返回TRUE,失败返回FALSE
  8. * */
  9. int Tail_insert(LinkList head,LNode **tail,ElemType data)
  10. {
  11. if(NULL==head)
  12. {
  13. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  14. return FALSE;
  15. }
  16. //创建一个新的结点p
  17. LNode *p=(LNode *)malloc(sizeof(LNode));
  18. p->data=data;
  19. p->next=NULL;
  20. //如果链表为空,那么插入的结点就是整个链表的尾结点
  21. if(NULL==head->next)
  22. {
  23. head->next=p;
  24. }
  25. else
  26. {
  27. (*tail)->next=p;
  28. }
  29. *tail=p;
  30. return TRUE;
  31. }

获取链表上的指定元素

思路:

1、从链表的第一个数据开始遍历

2、将遍历到的每一个结点上的数据域与需要获取/查找的元素比较

3、如果相等则返回该结点的地址

4、如果不相等则继续往后遍历

5、如果遍历到链表末尾依然没有找到则返回NULL

  1. //获取链表上的指定的元素
  2. /*
  3. * @brief 获取链表上的指定元素
  4. * @param head 需要查找链表的头指针
  5. * @param data 需要查找的元素
  6. * @return 成功返回结点所在的地址,失败返回NULL
  7. * */
  8. LNode * Get_elem(LinkList head,ElemType data)
  9. {
  10. if(NULL==head)
  11. {
  12. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  13. return FALSE;
  14. }
  15. LNode *t;
  16. t=head->next;
  17. while(t!=NULL)
  18. {
  19. if(t->data==data)
  20. return t;
  21. t=t->next;
  22. }
  23. return NULL;
  24. }

获取链表上指定位置上的元素

思路:

1、从链表的第一个数据结点开始遍历

2、每遍历一个结点遍历次数都加一,同时判断是否遍历到了链表的末尾

3、如果遍历到了链表的末尾返回NULL

4、遍历到了指定位置返回结点指针

  1. //获取链表指定位置的元素
  2. /*
  3. * @brief 获取指定位置的元素
  4. * @param head 需要遍历的链表的头指针
  5. * @param
  6. * @return 成功返回结点所在的地址,失败返回NULL
  7. * */
  8. LNode *Get_elem_BY_Index(LinkList head,unsigned int index)
  9. {
  10. if(NULL==head)
  11. {
  12. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  13. return FALSE;
  14. }
  15. //使用一个临时指针指向链表的第一个数据结点
  16. LNode *t=head->next;
  17. int i=1;
  18. //判断是否遍历到了链表的末尾或者遍历到了指定位置
  19. while(i<=index && t!=NULL)
  20. {
  21. i++;
  22. t=t->next;
  23. }
  24. return t;
  25. }

删除链表上指定位置的元素

思路:

1、使用临时指针t从链表的第一个数据结点开始遍历

2、使用临时指针遍历p保存遍历到的结点的前驱结点

3、每遍历一个结点遍历次数+1,指针p与随之往后移动,同时判断是否遍历到链表的末尾

4、如果遍历到链表的末尾则返回FALSE

5、如果遍历到的位置恰好是最后一个结点(尾结点),则将尾指针指向该结点的前一个结点

6、如果遍历到的结点是中间结点,则将前驱结点指向遍历到的结点的下一个结点

  1. /*
  2. * @brief 删除指定位置的结点
  3. * @param head 需要删除的链表的头指针
  4. * @param tail 需要删除的链表的尾指针地址
  5. * @param index 需要删除的元素的位置
  6. * @return 成功返回TRUE,失败返回FALSE
  7. * */
  8. int Delete_By_index(LinkList head,LNode **tail,uint index)
  9. {
  10. if(NULL==head)//如果是空指针
  11. {
  12. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  13. return FALSE;
  14. }
  15. LNode *t=head->next;
  16. LNode *p=head;
  17. int i=1;
  18. while(i<index && t!=NULL)//轮询到达指定位置
  19. {
  20. i++;
  21. t=t->next;
  22. p=p->next;
  23. }
  24. if(t==NULL)
  25. {
  26. printf("【%s %d】 can not delete\n ",__FUNCTION__,__LINE__ );
  27. return FALSE;
  28. }
  29. //如果刚好遍历到了最后一个结点
  30. if(t->next==NULL)
  31. {
  32. *tail=p;
  33. (*tail)->next=NULL;
  34. free(t);
  35. return TRUE;
  36. }
  37. //如果是中间结点
  38. p->next=t->next;
  39. free(t);
  40. return TRUE;
  41. }

删除链表上指定元素所在的结点

思路:

1、使用临时指针t从链表的第一个数据结点开始遍历,一直遍历到链表的末尾

2、使用临时指针p保存遍历到的结点的前驱结点(换句话说就是保存前一个结点)

3、将遍历到的每一个结点上的数据域与需要删除的元素作比较

4、如果遍历到的结点是尾结点,将尾指针tail指向所需要删除的结点的前驱结点p,为指针p->next=NULL,释放当前结点free(t),返回TRUE

5、如果遍历到的结点是中间结点,前驱结点指向当前结点的下一个结点p->next=t->next,释放当前结点free(t),临时指针t指向下一个结点继续开始往后遍历

  1. /*
  2. * @brief 删除链表上指定元素所在的结点
  3. * @param head 需要删除的链表的头指针
  4. * @param tail 需要删除的链表的尾指针地址
  5. * @param index 需要删除的元素的位置
  6. * @return 成功返回TRUE,失败返回FALSE
  7. * */
  8. int Delete_By_elem_Value(LinkList head,LNode **tail,ElemType data)
  9. {
  10. if(NULL==head)
  11. {
  12. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  13. return FALSE;
  14. }
  15. LNode * t=head->next;
  16. LNode * p=head;
  17. while (t!=NULL)
  18. {
  19. //如果遍历到了需要删除的结点
  20. if(t->data==data)
  21. {
  22. //如果当前结点是尾结点
  23. if(t->next==NULL)
  24. {
  25. *tail=p;
  26. (*tail)->next=NULL;
  27. free(t);
  28. return TRUE;
  29. }
  30. p->next=t->next;
  31. free(t);
  32. t=p->next;
  33. }
  34. else
  35. {
  36. t=t->next;
  37. p=p->next;
  38. }
  39. }
  40. return TRUE;
  41. }

在链表指定位置前插入一个结点

思路:

1、使用一个临时指针t从链表的第一个数据结点开始遍历。

2、使用临时指针p保存遍历到的结点的前驱结点

3、每遍历一个结点遍历次数就加1,指针p与之往后移动,同是否遍历到了链表的末尾

4、如果遍历到了链表的末尾则返回FALSE

5、如果遍历到了指定位置,创建一个新的结点n.

6、将前驱结点p指向新的结点n,p->next=n,将新的结点指向遍历到的结点,n->next=t,

7、返回TRUE

  1. //在链表指定位置/指定位置前插入一个结点
  2. /*
  3. * @brief 在链表指定位置前插入一个结点
  4. * @param head 需要插入的链表的头指针
  5. * @param index 需要插入的元素位置
  6. * @param data 需要插入的元素的值
  7. * @return 成功返回TRUE,失败返回FALSE
  8. * */
  9. int Insert_By_index(LNode *head,uint index,ElemType data)
  10. {
  11. if(NULL==head)
  12. {
  13. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  14. return FALSE;
  15. }
  16. LNode *t=head->next;
  17. LNode *p=head;
  18. int i=1;
  19. while(i<index && t!=NULL)
  20. {
  21. i++;
  22. t=t->next;
  23. p=p->next;
  24. }
  25. //如果将整个链表都遍历完了,则说明需要插入的位置不在链表上,(超出了链表的长度)
  26. if(NULL==t)
  27. {
  28. printf("[%s %d] index:%d out of range ...",__FUNCTION__ ,__LINE__,index);
  29. return FALSE;
  30. }
  31. //创建一个新的结点n
  32. LNode * n;
  33. n=(LNode *)malloc(sizeof(LNode));
  34. n->next=NULL;
  35. n->data=data;
  36. //如果是中间结点将前驱结点p指向新点n,p->next=n,将新的结点指向遍历到的结点,n->next = t
  37. p->next=n;
  38. n->next=t;
  39. return TRUE;
  40. }

插入一个元素使得整个链表依然保持为升序

思路:

找到一个比需要插入的元素大的结点,在这个结点的前面插入新的结点

1、使用临时指针p保存遍历到的节点的前驱结点

2、使用临时指针t从链表的第一个数据开始遍历

3、每遍历一一个结点遍历的次数都加1,指针p随之往后移动,同时判断遍历到的结点是否比插入的元素大

4、如果比插入的元素小则继续往后遍历,

5、如果比插入的元素大,则创建一个新的结点n

6、判断该结点是否为尾结点,

7、如果不是前驱结点将前驱结点p指向新的结点n,p->next=n,将新的结点指向遍历到的结点,n->next=t

8、如果将整个链表遍历完毕依然没有找到比需要插入的元素大的结点 则说明该结点将会是整个链表上的最大结点,应插入到链表的末尾。

  1. //插入一个元素使得整个链表依然保持为升序(原列表为升序序列)
  2. /*
  3. * @brief 插入一个结点使原链表依然保持原有的升序排列
  4. * @param head 头指针
  5. * @param tail 指向尾指针的地址
  6. * @param data 结点的数据域
  7. * return 返回FALSE或者TRUE
  8. * */
  9. int ascending_insert(LNode * head,LNode **tail,ElemType data)
  10. {
  11. if(NULL==head)
  12. {
  13. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  14. return FALSE;
  15. }
  16. //创建一个新的结点n
  17. LNode *n;
  18. n=(LNode *)malloc(sizeof(LNode));
  19. n->data=data;
  20. n->next=NULL;
  21. LNode *t=head->next;
  22. LNode *p=head;
  23. while(t!=NULL)
  24. {
  25. if(t->data<=data)
  26. {
  27. t=t->next;
  28. p=p->next;
  29. continue;
  30. }
  31. //前驱结点p指向新的结点n,p->next=n,将新的结点指向遍历到的结点,n->next=t;
  32. p->next=n;
  33. n->next=t;
  34. break;
  35. }
  36. //如果将整个链表遍历完毕依然没有找到需要插入的元素的结点,则说明该新结点是整个链表上最大的结点,应该插入到链表的结尾
  37. p->next=n;
  38. *tail=n;//尾指针指向尾结点
  39. return TRUE;
  40. }

销毁链表

思想:

1、使用临时指针t从链表的第一个数据开始遍历,直到遍历到链表的末尾

2、每遍历到一个结点首先将头结点的next赋值尾当前结点的下一个结点head->next=t->next,然后临时指针t指向下一个结点t=head->next

3、如果整个链表遍历完毕则删除结点

  1. //销毁链表
  2. /*
  3. * @brief
  4. * @param
  5. * @return
  6. * */
  7. int List_destroy(LNode *head)
  8. {
  9. if(NULL==head)
  10. {
  11. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  12. return FALSE;
  13. }
  14. LNode *t=head->next;
  15. while(t==NULL)
  16. {
  17. head->next=t->next;
  18. free(t);
  19. t=head->next;
  20. }
  21. //把头结点也释放掉
  22. free(head);
  23. return TRUE;
  24. }

总的代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define FALSE 0
  4. #define TRUE 1
  5. typedef unsigned int uint;
  6. /*
  7. * 单项链表的结点
  8. * */
  9. typedef int ElemType ;
  10. typedef struct LNode{
  11. ElemType data;//数据域
  12. struct LNode *next;//指针域,指向当前结点的直接后继
  13. } LNode,*LinkList;//LinkList 的类型为LNode*
  14. /*
  15. * @brief:单项链表的初始化
  16. * @return 返回头结点的地址
  17. * */
  18. LinkList List_Init()
  19. {
  20. LNode *t;
  21. t=(LNode *)malloc(sizeof(LNode));//创建一个头节点
  22. t->next=NULL;
  23. LinkList head;//定义一个头指针
  24. head = t;//头指针指向头节点
  25. return head;
  26. }
  27. //单项链表的头插法
  28. /*
  29. * @brief 头插法插入一个结点
  30. * @param 需要插入链表的头指针
  31. * @param 需要插入的数据
  32. * return 成功返回TRUE,失败返回FALSE
  33. * */
  34. int Head_Insert(LinkList head,ElemType data)
  35. {
  36. if(NULL==head)
  37. return FALSE;
  38. //创建一个新的结点p
  39. LNode *p=(LNode *)malloc(sizeof(LNode));
  40. p->data=data;
  41. //将新的结点p的next指向头结点的下一个结点(之前的上一个结点)(head->next)
  42. p->next=head->next;
  43. //头结点的next指向新的结点p
  44. head->next=p;
  45. return TRUE;
  46. }
  47. //(修改Head_Insert函数)//获取尾指针
  48. /*
  49. * @brief 头插法插入一个结点
  50. * @param head 需要插入链表的头指针
  51. * @param tail 尾结点指针的地址
  52. * @param date 需要插入的数据
  53. * return 成功返回TRUE,失败返回FALSE
  54. * */
  55. int Change_Head_Insert(LinkList head,LNode **tail,ElemType data)
  56. {
  57. if(NULL==head)
  58. {
  59. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  60. return FALSE;
  61. }
  62. //创建一个新的结点p
  63. LNode *p=(LNode *)malloc(sizeof(LNode));
  64. p->data=data;
  65. p->next=NULL;
  66. //如果链表为空,那么插入的结点就是整个链表的尾结点
  67. if(NULL==head->next)
  68. *tail=p;
  69. //将新的结点p的next指向头结点的下一个结点(head->next)
  70. p->next=head->next;
  71. //头结点的next指向新的结点p
  72. head->next=p;
  73. return TRUE;
  74. }
  75. //单项链表的尾接法
  76. /*
  77. * @brief 头插法插入一个结点
  78. * @param head 需要插入链表的头指针
  79. * @param tail 尾结点指针的地址
  80. * @param date 需要插入的数据
  81. * return 成功返回TRUE,失败返回FALSE
  82. * */
  83. int Tail_insert(LinkList head,LNode **tail,ElemType data)
  84. {
  85. if(NULL==head)
  86. {
  87. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  88. return FALSE;
  89. }
  90. //创建一个新的结点p
  91. LNode *p=(LNode *)malloc(sizeof(LNode));
  92. p->data=data;
  93. p->next=NULL;
  94. //如果链表为空,那么插入的结点就是整个链表的尾结点
  95. if(NULL==head->next)
  96. {
  97. head->next=p;
  98. }
  99. else
  100. {
  101. (*tail)->next=p;
  102. }
  103. *tail=p;
  104. return TRUE;
  105. }
  106. //单项链表的打印
  107. /*
  108. * @brief 输出链表中的所有结点
  109. * @param head 链表的头指针
  110. * @return 成功返回TRUE ,失败返回FALSE
  111. * */
  112. int Print_List(LinkList head)
  113. {
  114. if(NULL==head)
  115. return FALSE;
  116. //使用一个临时指针对链表进行遍历
  117. LNode *p=head->next;
  118. while(p!=NULL)
  119. {
  120. printf("[%d]",p->data);
  121. p=p->next;
  122. }
  123. printf("\n");
  124. return TRUE;
  125. }
  126. //获取链表上的指定的元素
  127. /*
  128. * @brief 获取链表上的指定元素
  129. * @param head 需要查找链表的头指针
  130. * @param data 需要查找的元素
  131. * @return 成功返回结点所在的地址,失败返回NULL
  132. * */
  133. LNode * Get_elem(LinkList head,ElemType data)
  134. {
  135. if(NULL==head)
  136. {
  137. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  138. return FALSE;
  139. }
  140. LNode *t;
  141. t=head->next;
  142. while(t!=NULL)
  143. {
  144. if(t->data==data)
  145. return t;
  146. t=t->next;
  147. }
  148. return NULL;
  149. }
  150. //获取链表指定位置的元素
  151. /*
  152. * @brief 获取指定位置的元素
  153. * @param head 需要遍历的链表的头指针
  154. * @param
  155. * @return 成功返回结点所在的地址,失败返回NULL
  156. * */
  157. LNode *Get_elem_BY_Index(LinkList head,unsigned int index)
  158. {
  159. if(NULL==head)
  160. {
  161. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  162. return FALSE;
  163. }
  164. //使用一个临时指针指向链表的第一个数据结点
  165. LNode *t=head->next;
  166. int i=1;
  167. //判断是否遍历到了链表的末尾或者遍历到了指定位置
  168. while(i<=index && t!=NULL)
  169. {
  170. i++;
  171. t=t->next;
  172. }
  173. return t;
  174. }
  175. /*
  176. * @brief 删除链表上指定位置的元素
  177. * @param head 需要删除的链表的头指针
  178. * @param tail 需要删除的链表的尾指针地址
  179. * @param index 需要删除的元素的位置
  180. * @return 成功返回TRUE,失败返回FALSE
  181. * */
  182. int Delete_By_index(LinkList head,LNode **tail,uint index)
  183. {
  184. if(NULL==head)
  185. {
  186. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  187. return FALSE;
  188. }
  189. LNode *t=head->next;
  190. LNode *p=head;
  191. int i=1;
  192. while(i<index && t!=NULL)
  193. {
  194. i++;
  195. t=t->next;
  196. p=p->next;
  197. }
  198. if(t==NULL)
  199. {
  200. printf("【%s %d】 can not delete\n ",__FUNCTION__,__LINE__ );
  201. return FALSE;
  202. }
  203. //如果刚好遍历到了最后一个结点
  204. if(t->next==NULL)
  205. {
  206. *tail=p;
  207. (*tail)->next=NULL;
  208. free(t);
  209. return TRUE;
  210. }
  211. //如果是中间结点
  212. p->next=t->next;
  213. free(t);
  214. return TRUE;
  215. }
  216. /*
  217. * @brief 删除链表上指定元素所在的结点
  218. * @param head 需要删除的链表的头指针
  219. * @param tail 需要删除的链表的尾指针地址
  220. * @param index 需要删除的元素的位置
  221. * @return 成功返回TRUE,失败返回FALSE
  222. * */
  223. int Delete_By_elem_Value(LinkList head,LNode **tail,ElemType data)
  224. {
  225. if(NULL==head)
  226. {
  227. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  228. return FALSE;
  229. }
  230. LNode * t=head->next;
  231. LNode * p=head;
  232. while (t!=NULL)
  233. {
  234. //如果遍历到了需要删除的结点
  235. if(t->data==data)
  236. {
  237. //如果当前结点是尾结点
  238. if(t->next==NULL)
  239. {
  240. *tail=p;
  241. (*tail)->next=NULL;
  242. free(t);
  243. return TRUE;
  244. }
  245. p->next=t->next;
  246. free(t);
  247. t=p->next;
  248. }
  249. else
  250. {
  251. t=t->next;
  252. p=p->next;
  253. }
  254. }
  255. return TRUE;
  256. }
  257. //在链表指定位置/指定位置前插入一个结点
  258. /*
  259. * @brief 在链表指定位置前插入一个结点
  260. * @param head 需要插入的链表的头指针
  261. * @param index 需要插入的元素位置
  262. * @param data 需要插入的元素的值
  263. * @return 成功返回TRUE,失败返回FALSE
  264. * */
  265. int Insert_By_index(LNode *head,uint index,ElemType data)
  266. {
  267. if(NULL==head)
  268. {
  269. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  270. return FALSE;
  271. }
  272. LNode *t=head->next;
  273. LNode *p=head;
  274. int i=1;
  275. while(i<index && t!=NULL)
  276. {
  277. i++;
  278. t=t->next;
  279. p=p->next;
  280. }
  281. //如果将整个链表都遍历完了,则说明需要插入的位置不在链表上,(超出了链表的长度)
  282. if(NULL==t)
  283. {
  284. printf("[%s %d] index:%d out of range ...",__FUNCTION__ ,__LINE__,index);
  285. return FALSE;
  286. }
  287. //创建一个新的结点n
  288. LNode * n;
  289. n=(LNode *)malloc(sizeof(LNode));
  290. n->next=NULL;
  291. n->data=data;
  292. //如果是中间结点将前驱结点p指向新点n,p->next=n,将新的结点指向遍历到的结点,n->next = t
  293. p->next=n;
  294. n->next=t;
  295. return TRUE;
  296. }
  297. //插入一个元素使得整个链表依然保持为升序(原列表为升序序列)
  298. /*
  299. * @brief 插入一个结点使原链表依然保持原有的升序排列
  300. * @param head 头指针
  301. * @param tail 指向尾指针的地址
  302. * @param data 结点的数据域
  303. * return 返回FALSE或者TRUE
  304. * */
  305. int ascending_insert(LNode * head,LNode **tail,ElemType data)
  306. {
  307. if(NULL==head)
  308. {
  309. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  310. return FALSE;
  311. }
  312. //创建一个新的结点n
  313. LNode *n;
  314. n=(LNode *)malloc(sizeof(LNode));
  315. n->data=data;
  316. n->next=NULL;
  317. LNode *t=head->next;
  318. LNode *p=head;
  319. while(t!=NULL)
  320. {
  321. if(t->data<=data)
  322. {
  323. t=t->next;
  324. p=p->next;
  325. continue;
  326. }
  327. //前驱结点p指向新的结点n,p->next=n,将新的结点指向遍历到的结点,n->next=t;
  328. p->next=n;
  329. n->next=t;
  330. break;
  331. }
  332. //如果将整个链表遍历完毕依然没有找到需要插入的元素的结点,则说明该新结点是整个链表上最大的结点,应该插入到链表的结尾
  333. p->next=n;
  334. *tail=n;//尾指针指向尾结点
  335. return TRUE;
  336. }
  337. //销毁链表
  338. /*
  339. * @brief
  340. * @param
  341. * @return
  342. * */
  343. int List_destroy(LNode *head)
  344. {
  345. if(NULL==head)
  346. {
  347. printf("【%s %d】 head pointer is NULL\n ",__FUNCTION__,__LINE__ );
  348. return FALSE;
  349. }
  350. LNode *t=head->next;
  351. while(t==NULL)
  352. {
  353. head->next=t->next;
  354. free(t);
  355. t=head->next;
  356. }
  357. //把头结点也释放掉
  358. free(head);
  359. return TRUE;
  360. }
  361. int main() {
  362. printf("Hello, World!\n");
  363. //创建一个链表 、 初始化一个链表
  364. LNode *T=List_Init();
  365. //定义一个指针,指向链表的最后一个结点(尾结点)
  366. LNode * tail=NULL;
  367. //定义一个指针接受获取的值
  368. LNode *find;
  369. int i=0;
  370. for(i=0;i<10;i++)
  371. {
  372. // Change_Head_Insert(T,&tail,100+i);//头插法
  373. Tail_insert(T,&tail,100+i);//尾插法
  374. }
  375. Print_List(T);
  376. printf("tail:%d\n",tail->data);
  377. //获取链表上的指定元素
  378. find=Get_elem(T,103);
  379. if(find!=NULL)
  380. {
  381. printf("this data:%d\n",find->data);
  382. } else
  383. printf("NO this data\n");
  384. //获取链表上指定位置的元素
  385. find=Get_elem_BY_Index(T,3);
  386. if(find!=NULL)
  387. {
  388. printf("this location:%d\n",find->data);
  389. } else
  390. printf("NO this location\n");
  391. //删除链表上指定位置的元素
  392. Delete_By_index(T,&tail,3);
  393. printf("chance data:");
  394. Print_List(T);
  395. //删除链表上指定元素所在的结点
  396. Delete_By_elem_Value(T,&tail,100);
  397. printf("chance elem:");
  398. Print_List(T);
  399. //在链表指定位置插入一个结点
  400. Insert_By_index(T,1,1);
  401. printf("insert index 1 data 1 :");
  402. Print_List(T);
  403. //插入一个元素使得整个链表依然保持升序
  404. ascending_insert(T,&tail,102);
  405. printf("插入后的链表:");
  406. Print_List(T);
  407. //销毁链表
  408. List_destroy(T);
  409. printf("销毁后的链表:");
  410. return 0;
  411. }

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号

        
cppcmd=keepalive&