当前位置:   article > 正文

数据结构——C语言实现链表

c语言实现链表

目录

一. 链表的概念

二. 单链表的增删查改

1.单链表的定义

2.单链表的头插与头删

3.单链表的尾插与尾删

4.单链表的中间插入删除

5.单链表的查找

三. 带头循环双向链表的增删查改

1.带头循环双向链表的定义

2.带头循环双向链表的头插与头删

3.带头循环双向链表的尾插与尾删

4.带头循环双向链表的中间插入删除

5.带头循环双向链表的查找


一. 链表的概念

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。

在这里介绍链表中的两种结构

在这里插入图片描述

在这里插入图片描述

无头单向非循环列表:结构简单,一般不会单独用来存放数据。实际中更多是作为其他数据结构的子结构,比如说哈希桶等等。
带头双向循环链表:结构最复杂,一般单独存储数据。实际中经常使用的链表数据结构,都是带头双向循环链表。这个结构虽然复杂,但是使用代码实现后会发现这个结构会带来很多优势,实现反而简单了。

二. 单链表的增删查改

1.单链表的定义

在C语言中我们一般创建一个结构体来作为链表的结点

  1. typedef int SLDataType;
  2. typedef struct SListNode
  3. {
  4. SLDataType data;
  5. struct SListNode* next;
  6. }SListNode;

 创建初始化一个节点:

  1. void SListInitNode(SListNode** plist, SLDataType x)
  2. {
  3. assert(plist);
  4. *plist = (SListNode*)malloc(sizeof(SListNode));
  5. assert(*plist);
  6. (*plist)->data = x;
  7. (*plist)->next = NULL;
  8. }

2.单链表的头插与头删

1.头插

  1. void SListPushFront(SListNode** plist, SLDataType x)
  2. {
  3. assert(plist);
  4. SListNode* ptr = *plist;
  5. SListInitNode(plist, x);
  6. (*plist)->next = ptr;
  7. }

2.头删

  1. void SListPopFront(SListNode** plist)
  2. {
  3. assert(*plist);
  4. assert(plist);
  5. SListNode* ptr = (*plist)->next;
  6. free(*plist);
  7. *plist = ptr;
  8. }

3.单链表的尾插与尾删

1.尾插

  1. void SListPushBack(SListNode** plist, SLDataType x)
  2. {
  3. assert(plist);
  4. if (*plist == NULL)
  5. {
  6. SListInitNode(plist, x);
  7. }
  8. else
  9. {
  10. SListNode* ptr = *plist;
  11. while (ptr->next)
  12. {
  13. ptr = ptr->next;
  14. }
  15. SListInitNode(&(ptr->next), x);
  16. }
  17. }

2.尾删

  1. void SListPopBack(SListNode** plist)
  2. {
  3. assert(plist);
  4. assert(*plist);
  5. if ((*plist)->next == NULL)
  6. {
  7. free(*plist);
  8. *plist = NULL;
  9. }
  10. else
  11. {
  12. SListNode* ptr = *plist;
  13. while (ptr->next->next)
  14. {
  15. ptr = ptr->next;
  16. }
  17. free(ptr->next);
  18. ptr->next = NULL;
  19. }
  20. }

4.单链表的中间插入删除

1.在pos位置之后插入

为什么不在pos位置之前插入?

在pos位置之前插入需要传单链表的二级指针

1.用来解决pos指向单链表的头部出现的头插情况

2.用来寻找插入位置的前一个位置,以改变其指向

  1. void SListInsertAfter(SListNode* pos, SLDataType x)
  2. {
  3. assert(pos);
  4. SListNode* ptr = NULL;
  5. ptr = (SListNode*)malloc(sizeof(SListNode));
  6. assert(ptr);
  7. ptr->data = x;
  8. ptr->next = pos->next;
  9. pos->next = ptr;
  10. }

2.在pos位置之后删除

为什么不删除pos位置?
删除pos位置同样需要传入单链表的二级指针,

1.用来解决pos指向单链表的头部出现的单链表指针指向的改变

2.用来寻找pos位置的前一个位置,以改变其指向

  1. void SListEraseAfter(SListNode* pos)
  2. {
  3. assert(pos);
  4. assert(pos->next);
  5. SListNode* ptr = pos->next;
  6. pos->next = pos->next->next;
  7. free(ptr);
  8. ptr = NULL;
  9. }

5.单链表的查找

  1. SListNode* SListFind(SListNode* plist, SLDataType x)
  2. {
  3. assert(plist);
  4. while (plist)
  5. {
  6. if (plist->data == x)
  7. return plist;
  8. plist = plist->next;
  9. }
  10. return NULL;
  11. }

三. 带头循环双向链表的增删查改

1.带头循环双向链表的定义

在C语言中我们一般创建一个结构体来作为链表的结点

  1. typedef int LDataType;
  2. typedef struct ListNode
  3. {
  4. LDataType data;
  5. struct ListNode* next;
  6. struct ListNode* prev;
  7. }ListNode;

创建一个节点:

  1. ListNode* BuyListNode()
  2. {
  3. ListNode* tmp = (ListNode*)malloc(sizeof(ListNode));
  4. if (tmp == NULL)
  5. {
  6. perror("malloc");
  7. }
  8. return tmp;
  9. }

2.带头循环双向链表的头插与头删

1.头插

  1. void ListPushfront(ListNode* phead, LDataType x)
  2. {
  3. assert(phead);
  4. ListNode* newnode = BuyListNode();
  5. ListNode* tail = phead->next;
  6. phead->next = newnode;
  7. newnode->next = tail;
  8. newnode->prev = phead;
  9. tail->prev = newnode;
  10. newnode->data = x;
  11. //ListInsert(phead->next, x);
  12. }

2.头删

  1. void ListPopFront(ListNode* phead)
  2. {
  3. assert(phead);
  4. ListNode* tail = phead->next;
  5. tail->next->prev = phead;
  6. phead->next = tail->next;
  7. free(tail);
  8. //ListErase(phead->next);
  9. }

3.带头循环双向链表的尾插与尾删

1.尾插

  1. void ListPushBack(ListNode* phead, LDataType x)
  2. {
  3. ListNode* plist = BuyListNode();
  4. ListNode* tail = phead->prev;
  5. tail->next = plist;
  6. plist->prev = tail;
  7. plist->next = phead;
  8. phead->prev = plist;
  9. plist->data = x;
  10. //ListInsert(phead, x);
  11. }

2.尾删

  1. void ListPopBack(ListNode* phead)
  2. {
  3. assert(phead);
  4. ListNode* tail = phead->prev;
  5. tail->prev->next = phead;
  6. phead->prev = tail->prev;
  7. free(tail);
  8. //ListErase(phead->prev);
  9. }

4.带头循环双向链表的中间插入删除

1.插入

  1. void ListInsert(ListNode* pos, LDataType x)
  2. {
  3. assert(pos);
  4. ListNode* newnode = BuyListNode();
  5. pos->prev->next = newnode;
  6. newnode->prev = pos->prev;
  7. newnode->next = pos;
  8. pos->prev = newnode;
  9. newnode->data = x;
  10. }

2.删除

  1. void ListErase(ListNode* pos)
  2. {
  3. assert(pos);
  4. pos->prev->next = pos->next;
  5. pos->next->prev = pos->prev;
  6. free(pos);
  7. }

5.带头循环双向链表的查找

  1. ListNode* ListFind(ListNode* phead, LDataType x)
  2. {
  3. assert(phead);
  4. ListNode* cur = phead->next;
  5. while (phead != cur)
  6. {
  7. if (cur->data == x)
  8. return cur;
  9. cur = cur->next;
  10. }
  11. return NULL;
  12. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/455397
推荐阅读
相关标签
  

闽ICP备14008679号