【数据结构】-循环链表(单链表)

末蓝、 2023-02-27 14:59 101阅读 0赞

循环单链表-带头结点

  • 1.头文件及类型定义
  • 2.循环单链表结点类型定义
  • 3.函数声明
  • 4.基本操作
    • 4.1 初始化循环单链表
    • 4.2 判空
    • 4.3 判断表尾结点
    • 4.4 按位查找
    • 4.5 指定结点后插
    • 4.6 创建循环单链表
    • 4.7 遍历
    • 4.8 main函数
  • 5.小结

1.头文件及类型定义

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #define ElemType int

2.循环单链表结点类型定义

  1. typedef struct LNode {
  2. //定义单链表结点类型
  3. ElemType data; //每个结点存放一个数据元素
  4. struct LNode* next; //指针指向下一个结点
  5. }LNode, * LinkList;

3.函数声明

  1. /*函数声明*/
  2. bool InitList(LinkList& L); //1.初始化循环单链表
  3. bool Empty(LinkList L); //2.判空
  4. bool isTail(LinkList L, LNode* p); //3.判断表尾结点
  5. LNode* GetElem(LinkList L, int i); //4.按位查找
  6. bool InsertNextNode(LNode* p, ElemType e); //5.指定结点后插
  7. LinkList List_HeadInsert(LinkList& L); //6.头插法
  8. void PrintList(LinkList L); //7.遍历

4.基本操作

4.1 初始化循环单链表

  1. //1.初始化循环单链表(带头结点)
  2. bool InitList(LinkList& L) {
  3. L = (LNode*)malloc(sizeof(LNode)); //分配一个头结点
  4. if (L == NULL)
  5. return false; //内存不足,分配失败
  6. L->next = L; //头结点next指向头结点(仅此处与普通单链表有区别)
  7. return true;
  8. }

4.2 判空

  1. //2.判空
  2. bool Empty(LinkList L) {
  3. if (L->next == L) //仅此处与普通单链表有区别
  4. return true;
  5. else
  6. return false;
  7. //或者 return (L->next == L);
  8. }

4.3 判断表尾结点

  1. //3.判断结点p是否为循环单链表的表尾结点
  2. bool isTail(LinkList L, LNode* p) {
  3. if (p->next == L)
  4. return true;
  5. else
  6. return false;
  7. }

4.4 按位查找

  1. //4.查找函数-按位查找:返回第i个结点
  2. LNode* GetElem(LinkList L, int i) {
  3. if (i < 0)
  4. return NULL; //小于单链表长度
  5. LNode* p = L;
  6. int j = 0;
  7. while (p != NULL && j < i) {
  8. p = p->next;
  9. j++;
  10. }
  11. return p; //也可能返回NULL,当输入i大于单链表长度时
  12. }

4.5 指定结点后插

  1. //5.插入函数-指定结点后插:在指定结点之后插入元素e
  2. bool InsertNextNode(LNode* p, ElemType e) {
  3. if (p == NULL)
  4. return false;
  5. LNode* s = (LNode*)malloc(sizeof(LNode));
  6. if (s == NULL) //内存分配失败
  7. return false;
  8. s->data = e;
  9. s->next = p->next;
  10. p->next = s;
  11. return true;
  12. }

4.6 创建循环单链表

  1. //6.创建循环单链表:头插法
  2. LinkList List_HeadInsert(LinkList& L) {
  3. if (InitList(L)) //初始化循环单链表
  4. printf("循环单链表初始化成功!\n");
  5. else
  6. printf("循环单链表初始化失败!\n");
  7. if (Empty(L))
  8. printf("当前表为空!\n");
  9. else
  10. printf("当前表非空!\n");
  11. ElemType x;
  12. int i = 1; //用作记录插入第几个元素
  13. printf("开始创建循环单链表!\n请输入%d个元素:", i);
  14. scanf("%d", &x);
  15. while (x != 0) {
  16. if (InsertNextNode(L, x)) //头插法本质是头结点的后插操作
  17. printf("成功插入第%d个元素:%d\n", i, x);
  18. else
  19. printf("插入第%d个元素失败!\n", i);
  20. printf("请输入%d个元素:", ++i);
  21. scanf("%d", &x);
  22. }
  23. printf("循环单链表创建完成!\n");
  24. return L;
  25. }

4.7 遍历

  1. //7.遍历循环单链表
  2. void PrintList(LinkList L) {
  3. LNode* p;
  4. p = L->next;
  5. printf("遍历循环单链表:\n");
  6. while (p != L) {
  7. //此处判断与普通单链表有区别
  8. printf("%d\t", p->data);
  9. p = p->next;
  10. }
  11. printf("\n");
  12. }

4.8 main函数

  1. int main() {
  2. LinkList L;
  3. int i;
  4. /*以下操作只要涉及对循环单链表的改动,均遍历循环单链表*/
  5. /*1、头插法建立循环单链表*/
  6. L = List_HeadInsert(L);
  7. /*2、判空*/
  8. if (Empty(L))
  9. printf("当前表为空!");
  10. else
  11. printf("当前表非空!");
  12. PrintList(L);
  13. /*3、按位查找*/
  14. printf("请输入您要查找的位序i:");
  15. scanf("%d", &i);
  16. LNode* p = GetElem(L, i);
  17. printf("位序为%d的值为:%d\n", i, p->data);
  18. /*4.判断表尾结点*/
  19. if (isTail(L, p))
  20. printf("当前结点为表尾结点!\n");
  21. else
  22. printf("当前结点不是表尾结点!\n");
  23. //*5、指定结点后插,以按位查找的p结点为例*/
  24. ElemType e;
  25. printf("请输入您要后插的值:");
  26. scanf("%d", &e);
  27. if (InsertNextNode(p, e))
  28. printf("p结点后插成功,元素值为:%d\n", e);
  29. else
  30. printf("p结点后插失败!\n");
  31. /*5.再次判断表尾结点*/
  32. if (isTail(L, p))
  33. printf("当前结点为表尾结点!\n");
  34. else
  35. printf("当前结点不是表尾结点!\n");
  36. PrintList(L);
  37. return 0;
  38. }

5.小结

  1. 普通单链表和循环单链表的对比
    (1)不同点
    主要是初始化判空判断表尾结点遍历结束条件方面有微小的变化,主要原因就是循环单链表的表尾结点指向了头结点,而不是NULL。
    (2)相同点
    增删查以及创建操作没有改变。
  2. 说明
    上述代码主要是对循环单链表中与普通单链表有区别的操作进行了测试,其他基本操作与普通单链表基本一致。

发表评论

表情:
评论列表 (有 0 条评论,101人围观)

还没有评论,来说两句吧...

相关阅读