当前位置:   article > 正文

数据结构初阶之单链表(一)

数据结构初阶之单链表(一)

链表:按需申请释放

注意:链式结构在逻辑上是连续的,但是在物理上不一定连续

  1. //signal list table 单链表
  2. //signal link table 单链表
  3. typedef int SLTataType;
  4. typedef struct SListNode //signal 单的
  5. {
  6. SLTataType data; //数据域
  7. struct SListNode* next; //指针域
  8. }SLTNode;

先来浅浅写一个打印函数

  1. void PrintSLT(SLTNode * phead)
  2. {
  3. SLTNode * cur = phead;
  4. while (cur == NULL)
  5. {
  6. printf("%d->", cur->data);
  7. cur = cur->next;
  8. }
  9. printf("NULL\n");
  10. }

初始化链表

  1. int n;
  2. printf("请输入链表的长度:");
  3. scanf("%d", &n);
  4. printf("\n请依次输入每个结点的值:");

 由于需要定义一个结构体指针来存放链表中第一个数据的地址,因此

SLTNode* plist = NULL;

使用for循环来完成链表数据的输入,但是由于后面的诸多函数(例如增删查改)均需要节点函数,因此我们先来写一个节点函数

  1. SLTNode* BuySListNode(SLTDataType x)
  2. {
  3. SLTNode* newnode =(SLTNode *) malloc(sizeof(SLTNode));
  4. if (newnode == NULL)
  5. {
  6. perror("malloc fail");
  7. exit(-1);
  8. }
  9. newnode->data = x;
  10. newnode->next = NULL;
  11. return newnode;
  12. }

完成节点函数后,利用for循环实现链表的连接:

  1. for (size_t i = 0; i < n; i++)
  2. {
  3. int val;
  4. scanf("%d", &val);
  5. SLTNode* newnode = BuySListNode(val);
  6. }

连接完成以后,我们考虑到,假如 plist==NULL;

  1. if (plist == NULL)
  2. {
  3. plist = newnode;
  4. }

但是假如plist != NULL,则有头插和尾插两种情况,但由于尾插情况较为复杂,而且我们现在是在初始化链表,因此我们先讨论头插情况。

物理图如下:

 代码实现如下:

  1. newnode->next = plist;
  2. plist = newnode;

即代码汇总为

  1. for (size_t i = 0; i < n; i++)
  2. {
  3. int val;
  4. scanf("%d", &val);
  5. SLTNode* newnode = BuySListNode(val);
  6. // 头插
  7. newnode->next = plist;
  8. plist = newnode;
  9. }

那么问题来了,假如链表为空,需要对plist == NULL,进行分情况讨论吗,答案是不需要的,咱们看图说话。

整体代码如下:

  1. void PrintSLT(SLTNode* phead)
  2. {
  3. SLTNode * cur = phead;
  4. while (cur != NULL)
  5. {
  6. printf("%d->", cur->data);
  7. cur = cur->next;
  8. }
  9. printf("NULL\n");
  10. }
  11. SLTNode* BuySListNode(SLTDataType x)
  12. {
  13. SLTNode* newnode =(SLTNode *) malloc(sizeof(SLTDataType));
  14. if (newnode == NULL)
  15. {
  16. perror("malloc fail");
  17. exit(-1);
  18. }
  19. newnode->data = x;
  20. newnode->next = NULL;
  21. return newnode;
  22. }
  23. void Test1()
  24. {
  25. int n;
  26. printf("请输入链表的长度:");
  27. scanf("%d", &n);
  28. printf("\n请依次输入每个结点的值:");
  29. SLTNode* plist = NULL;
  30. for (size_t i = 0; i < n; i++)
  31. {
  32. int val;
  33. scanf("%d",& val);
  34. SLTNode* newnode = BuySListNode(val);
  35. //头插
  36. newnode->next = plist;
  37. plist = newnode;
  38. }
  39. PrintSLT(plist);
  40. }
  41. int main()
  42. {
  43. Test1();
  44. return 0;
  45. }

运行如下:

现在来实行尾插 :

代码实现如下:

  1. void SLTPushBack(SLTNode* phead, SLTDataType x)
  2. {
  3. //phead是形参 plist是实参
  4. SLTNode* newnode = BuySListNode(x);
  5. while (phead->next)
  6. {
  7. phead = phead->next;
  8. }
  9. phead->next = newnode;
  10. }

运行如下:

 现在又有一个新的问题来了,假如链表为空,那么要怎么插入呢?

此时就需要改变结构体指针,具体参考如下

  1. void SLTPushBack(SLTNode** phead, SLTDataType x)
  2. {
  3. //phead是形参 plist是实参
  4. SLTNode* newnode = BuySListNode(x);
  5. if (*phead == NULL)
  6. {
  7. *phead = newnode;
  8. }
  9. else
  10. {
  11. SLTNode* tail = *phead;
  12. while (tail->next)
  13. {
  14. tail = tail->next;
  15. }
  16. tail->next = newnode;
  17. }
  18. }

小tips:

1.改变结构体,需要用结构体指针

2.改变结构体指针,  需要用结构体指针的指针

头插尾插都写好了,我们再来写尾删头删

先来看结构图:

代码实现如下: 

  1. void SLTPopBack(SLTNode** phead, SLTDataType x)
  2. {
  3. //1.空
  4. assert(*phead);//暴力检查
  5. //2.一个节点
  6. //3.一个以上节点
  7. if ((*phead)->next == NULL)
  8. {
  9. free(*phead);
  10. *phead = NULL;
  11. }
  12. else
  13. {
  14. //法一:
  15. SLTNode* tailPrev = NULL;//表示tail前的那个结构体
  16. SLTNode* tail = *phead;
  17. while (tail->next)
  18. {
  19. tailPrev = tail;
  20. tail = tail->next;
  21. }
  22. free(tail);
  23. tailPrev->next = NULL;
  24. //法二:
  25. SLTNode* tail = *phead;
  26. while (tail->next->next)
  27. {
  28. tail = tail->next;
  29. }
  30. free(tail->next);
  31. tail->next = NULL;
  32. }
  33. }

运行如下:

头删

代码实现如下:

  1. void SLTPopFront(SLTNode** phead)
  2. {
  3. //
  4. assert(*phead);
  5. //非空
  6. SLTNode* newhead = (*phead)->next;
  7. free(*phead);
  8. *phead = newhead;
  9. }

运行如下:

接下来我们要进行:

//在pos位置插入x
void SLTInsert(SLTNode** phead, SLTNode* pos, SLTDataType x);

//在pos以后插入x
void SLTInsertAfter(SLTNode* pos, SLTDataType x);

//删除pos位置
void SLTErase(SLTNode** phead, SLTNode* pos, SLTDataType x);

//删除pos的后一个位置
void SLTEraseAfter(SLTNode* pos, SLTDataType x);

欲知后事如何,请看下回分解,今天就先到这里了。

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

闽ICP备14008679号