【数据结构】 循环双链表的基本操作 (C语言版)

目录

一、循环双链表

1、循环双链表的定义:

2、循环双链表的优缺点:

二、循环双链表的基本操作算法(C语言)

1、宏定义

2、创建结构体

3、循环双链表的初始化

4、循环双链表按位查找

5、循环双链表插入

6、循环双链表查找

7、循环双链表删除

8、求循环双链表长度

9、循环双链表清空

10、循环双链表销毁

11、头插法建立循环双链表

12、尾头插法建立循环双链表

13、输出链表元素

三、循环双链表的基本操作完整代码(C语言)

四、运行结果


一、循环双链表

1、循环双链表的定义:

循环双链表是一种特殊的双链表,其特点是尾节点的指针域指向头结点,形成一个环状结构。这种数据结构允许从链表的任意节点出发,通过后移操作,遍历整个循环双链表。

2、循环双链表的优缺点:

循环双链表的优点:

  1. 可以从任意节点出发,遍历整个链表,提高了遍历的灵活性。
  2. 在某些应用场景中,循环双链表可以提供更高的访问效率。

循环双链表的缺点:

  1. 插入和删除节点需要更多的时间来调整指针,因为需要维护链表的环状结构。
  2. 循环双链表的空间利用率相对较低,因为需要额外的指针来存储前驱和后继节点的信息。

二、循环双链表的基本操作算法(C语言)

1、宏定义
#define OK 1
#define ERROR 0

typedef char ElemType;
typedef int Status;
2、创建结构体
/**定义一个具有前驱指针和后继指针的双链表的结构体**/
typedef struct DuLNode {
    ElemType data;  //数据域
    struct DuLNode *prior; //指向直接前驱
    struct DuLNode *next; //指向直接后继
    //    struct DuLNode *prior,*next;		//前驱指针和后继指针
} DuLNode, *DuLinkList; //前者强调这是结点,后者强调这是链表
3、循环双链表的初始化
//循环双链表初始化
Status InitList(DuLinkList &head) {
    head = new DuLNode;
    head->prior = head;//循环双链表
    head->next = head;
    return OK;
}
4、循环双链表按位查找
//按位查找
DuLNode *GetElem(DuLinkList L, int i) {
    int j = 1;//因为有头结点,所以从1开始遍历
    if (i < 1) {//判断查找的位置是否合法
        printf("数值非法");
    }
    DuLNode *p = L->next;//初始化结点指针
    while (p != NULL && j < i) {
        p = p->next;
        j++;
    }
    return p;
}
5、循环双链表插入
//插入
Status ListInsert_Dul(DuLinkList &head, int i, ElemType e) {
   DuLinkList p = head;
   int j=0;
    while (p && (j<i-1)){
       p=p->next;
       j++;
   }
    if (!p || j > i-1){
        return ERROR;
   }
    //DuLinkList p = GetElem(head, i);
    if (!p) {
        return ERROR;
    }
    DuLNode *s = new DuLNode;
    s->data = e;
    s->prior = p->prior;
    p->prior->next = s;
    s->next = p;
    p->prior = s;

    return OK;
}
6、循环双链表查找
//查找
int LocateLinkListElem(DuLinkList head, ElemType e) {
    DuLinkList p = head->next;
    int j = 1;
    while (p != head && (p->data != e)) {//p != L p!=NULL
        p = p->next;
        j++;
    }
    if (p == head) { //p==L  !p<=>p==NULL
        return 0;
    }
    return j;
}
7、循环双链表删除
//删除
Status ListDelete_DuL(DuLinkList &head, int i, ElemType &e) {
    DuLinkList p=head;
    int j=0;
    while (p->next != head  && j <= i){  //p != L
        p=p->next;
        j++;
    }
    if (p->next == head){ //p==L
        return ERROR;
    }
    //调用按位查找函数
//    DuLinkList p = GetElem(head, i);
    if (!p) {
        return ERROR;
    }
    e = p->data;
    p->prior->next = p->next;
    p->next->prior = p->prior;
    delete p;
    return OK;
}
8、求循环双链表长度
//求双链表长度
Status GetLinkListLength(DuLinkList head) {
    DuLinkList p = head->next;
    int length = 0;
    while (p != head) {   //p!=NULL          //单链表不为空表时
        length++;
        p = p->next;
    }
    return length;
}
9、循环双链表清空
//清空
Status ClearList(DuLinkList &head) {
    DuLinkList p = head->next;
    DuLinkList q;
    while (p != head) { //p != L  p!=NULL
        q = p;
        p = p->next;
        delete q;
    }
    head->prior = head;
    head->next = head; //链表为空
    return OK;
}
10、循环双链表销毁
//销毁
Status DestroyList(DuLinkList &head) {

    DuLinkList p, q;//初始化两个指针,p用来free释放,q用来在p释放后将p指针指向下一个
    p = head->next;//删除带头链表头结点不删除
    q = p;
    while (p != head) {
        q = p->next;  //提前将q指向下一个
        delete p;    //释放p
        p = q;        //将p指向q所指向的下一个
    }
    head->next = NULL; //头结点指向NULL
    return OK;
    //printf("\n销毁成功\n");
}
11、头插法建立循环双链表
void CreateDLinkList_H(DuLinkList &head, int n) {
    InitList(head);
    for (int i = 0; i < n; i++) {
        DuLNode *p = new DuLNode;
        //scanf("%c",&p->data);
        p->data = getche();
        //cin >> p->data;
        p->next = head->next;
        if (head->next != NULL) {
            head->next->prior = p;
        }
        p->prior = head;
        head->next = p;
    }
}
12、尾头插法建立循环双链表
void CreateDoubleList_R(DuLinkList &head, int n) {
    InitList(head);
    DuLinkList r = head;  // 初始化 r 指针为头结点
    for (int i = 0; i < n; i++) {
        DuLNode *p = new DuLNode;
        //scanf("%c",&p->data);
        p->data = getche();
        //cin >> p->data;
        //p->next=NULL   p->next=head
        p->next = r->next;
        if (r->next != NULL) {
            r->next->prior = p;
        }
        p->prior = r;
        r->next = p;
        r = p;  // r 指向新插入的节点,更新尾指针
    }
    r->next = head;  // 将尾节点的 next 指针指向头结点,形成循环
}
13、输出链表元素
//输出链表元素
void printLinkList(DuLinkList head) {
    DuLinkList p = head->next;
    while (p != head) { //p != L
        printf("%c", p->data);
        p = p->next;
    }
    printf("\n");
}

三、循环双链表的基本操作 完整代码**(C语言)**

#include <stdio.h>
#include <conio.h>//getche()

#define OK 1
#define ERROR 0

typedef char ElemType;
typedef int Status;

/**定义一个具有前驱指针和后继指针的双链表的结构体**/
typedef struct DuLNode {
    ElemType data;  //数据域
    struct DuLNode *prior; //指向直接前驱
    struct DuLNode *next; //指向直接后继
    //    struct DuLNode *prior,*next;		//前驱指针和后继指针
} DuLNode, *DuLinkList; //前者强调这是结点,后者强调这是链表


//双链表初始化
Status InitList(DuLinkList &head) {
    head = new DuLNode;
    head->prior = head;//循环双链表
    head->next = head;
//    head->prior = NULL;
//    head->next = NULL;
    return OK;
}


//功能菜单
int choice() {
    printf("==================================\n");
    printf("         双链表操作功能菜单        \n");
    printf("1、插入元素  2、查询表长  3、按位查找\n");
    printf("4、按值查找  5、删除元素  6、销毁链表\n");
    printf("7、清空链表  8、批量插入  9、链表元素\n");
    printf("10、头插法创建双链表11、尾插法创建双链表\n");
    printf("==================================\n");
    return 0;
}

//按位查找
DuLNode *GetElem(DuLinkList L, int i) {
    int j = 1;//因为有头结点,所以从1开始遍历
    if (i < 1) {//判断查找的位置是否合法
        printf("数值非法");
    }
    DuLNode *p = L->next;//初始化结点指针
    while (p != NULL && j < i) {
        p = p->next;
        j++;
    }
    return p;
}

//插入
Status ListInsert_Dul(DuLinkList &head, int i, ElemType e) {
//    DuLinkList p = head;
//    int j=0;
//    while (p && (j<i-1)){
//        p=p->next;
//        j++;
//    }
//    if (!p || j > i-1){
//        return ERROR;
//    }
    DuLinkList p = GetElem(head, i);
    if (!p) {
        return ERROR;
    }
    DuLNode *s = new DuLNode;
    s->data = e;
    s->prior = p->prior;
    p->prior->next = s;
    s->next = p;
    p->prior = s;

    return OK;
}

//查找
int LocateLinkListElem(DuLinkList head, ElemType e) {
    DuLinkList p = head->next;
    int j = 1;
    while (p != head && (p->data != e)) {//p != L p!=NULL
        p = p->next;
        j++;
    }
    if (p == head) { //p==L  !p<=>p==NULL
        return 0;
    }
    return j;
}

//删除
Status ListDelete_DuL(DuLinkList &head, int i, ElemType &e) {
//    DuLinkList p=head;
//    int j=0;
//    while (p->next != head  && j <= i){  //p != L
//        p=p->next;
//        j++;
//    }
//    if (p->next == head){ //p==L
//        return ERROR;
//    }
    //调用按位查找函数
    DuLinkList p = GetElem(head, i);
    if (!p) {
        return ERROR;
    }
    e = p->data;
    p->prior->next = p->next;
    p->next->prior = p->prior;
    delete p;
    return OK;
}

//求双链表长度
Status GetLinkListLength(DuLinkList head) {
    DuLinkList p = head->next;
    int length = 0;
    while (p != head) {   //p!=NULL          //单链表不为空表时
        length++;
        p = p->next;
    }
    return length;
}


//清空
Status ClearList(DuLinkList &head) {
    DuLinkList p = head->next;
    DuLinkList q;
    while (p != head) { //p != L  p!=NULL
        q = p;
        p = p->next;
        delete q;
    }
    head->prior = head;
    head->next = head; //链表为空
    return OK;
}

//销毁
Status DestroyList(DuLinkList &head) {

    DuLinkList p, q;//初始化两个指针,p用来free释放,q用来在p释放后将p指针指向下一个
    p = head->next;//删除带头链表头结点不删除
    q = p;
    while (p != head) {
        q = p->next;  //提前将q指向下一个
        delete p;    //释放p
        p = q;        //将p指向q所指向的下一个
    }
    head->next = NULL; //头结点指向NULL
    return OK;
    //printf("\n销毁成功\n");
}

//头插法创建循环双链表
void CreateDLinkList_H(DuLinkList &head, int n) {
    InitList(head);
    for (int i = 0; i < n; i++) {
        DuLNode *p = new DuLNode;
        //scanf("%c",&p->data);
        p->data = getche();
        //cin >> p->data;
        p->next = head->next;
        if (head->next != NULL) {
            head->next->prior = p;
        }
        p->prior = head;
        head->next = p;
    }
}

//尾插法创建循环双链表
void CreateDoubleList_R(DuLinkList &head, int n) {
    InitList(head);
    DuLinkList r = head;  // 初始化 r 指针为头结点
    for (int i = 0; i < n; i++) {
        DuLNode *p = new DuLNode;
        //scanf("%c",&p->data);
        p->data = getche();
        //cin >> p->data;
        //p->next=NULL   p->next=head
        p->next = r->next;
        if (r->next != NULL) {
            r->next->prior = p;
        }
        p->prior = r;
        r->next = p;
        r = p;  // r 指向新插入的节点,更新尾指针
    }
    r->next = head;  // 将尾节点的 next 指针指向头结点,形成循环
}

//输出链表元素
void printLinkList(DuLinkList head) {
    DuLinkList p = head->next;
    while (p != head) { //p != L
        printf("%c", p->data);
        p = p->next;
    }
    printf("\n");
}

int main() {

    DuLinkList list;

    printf("双链表正在初始化....\n");
    int InitStatus = InitList(list);
    if (InitStatus == OK) {
        printf("双链表初始化成功!\n");
    } else {
        printf("双链表初始化失败!\n");
    }

    choice();

    while (1) {
        int flag;
        printf("请输入所需的功能编号:\n");
        scanf("%d", &flag);

        switch (flag) {//通过开关进行功能选择
            case 1: {//插入元素
                //ListInsert_Dul(list,1,'a');
                int insertIndex;
                ElemType inserElem;
                printf("请输入插入元素位置及插入元素(请在英文状态下输入例如:1,a): \n");
                scanf("%d,%c", &insertIndex, &inserElem);
                Status InsertS = ListInsert_Dul(list, insertIndex, inserElem);
                if (InsertS == OK) {
                    printf("向双循环链表%d个位置,插入元素为%c成功!\n\n", insertIndex, inserElem);
                } else {
                    printf("向双循环链表插入元素失败!\n\n");
                }
            }
                break;
            case 2: {//求单链表的长度
                int length = GetLinkListLength(list);
                printf("循环双链表的长度为:%d。 \n\n", length);
            }
                break;
            case 3: {//取值
                Status GetIndex;
                printf("请输入需要查询的元素的位置:\n");
                scanf("%d", &GetIndex);
                DuLinkList GetStatus = GetElem(list, GetIndex);
                ElemType GetElem = GetStatus->data;
                if (GetStatus != NULL) {
                    printf("从双链表中获取第%d位置元素成功,所获取到的元素为:%c。\n\n", GetIndex, GetElem);
                } else {
                    printf("从双链表中获取第%d位置元素失败!\n\n", GetIndex);
                }
            }
                break;
            case 4: {//查找
                ElemType LocateElem;
                printf("请输入想要查找元素:\n");
                getchar();    //用于接收回车
                scanf("%c", &LocateElem);
                Status LocateIndex = LocateLinkListElem(list, LocateElem);
                if (LocateIndex > 0) {
                    printf("从双链表中查找元素%c成功,它在循环链表中的位置为第%d个!\n\n", LocateElem, LocateIndex);
                } else {
                    printf("从双链表中查找元素%c失败!\n\n", LocateElem);
                }
            }
                break;
            case 5: {//删除
                //ListDelete_DuL(list,1);
                Status DeleteIndex;
                printf("请输入想要删除元素的位置:\n");
                scanf("%d", &DeleteIndex);
                ElemType DeleteElem;
                ElemType DeleteStatus = ListDelete_DuL(list, DeleteIndex, DeleteElem);
                if (DeleteStatus == OK) {
                    printf("删除双链表第%d个位置的元素成功,删除的元素为:%c。\n\n", DeleteIndex, DeleteElem);
                } else {
                    printf("删除双链表第%d个位置的元素失败!\n\n", DeleteIndex);
                }
            }
                break;
            case 6: {//销毁
                Status DestoryStatus = DestroyList(list);
                if (DestoryStatus == OK) {
                    printf("双环链表销毁成功!\n\n");
                } else {
                    printf("双链表销毁失败!\n\n");
                }
            }
                break;
            case 7: {//清空
                Status ClearStatus = ClearList(list);
                if (ClearStatus == OK) {
                    printf("双链表清空成功!\n\n");
                } else {
                    printf("双链表清空失败!\n\n");
                }
            }
                break;
            case 8: {//批量插入
                int on;
                printf("请输入想要插入的元素个数:\n");
                scanf("%d", &on);
                ElemType array[on];
                for (int i = 1; i <= on; i++) {
                    getchar();
                    printf("向双链表第%d个位置插入元素为:", (i));
                    scanf("%c", &array[i]);
                }

                for (int i = 1; i <= on; i++) {
                    Status InsertStatus = ListInsert_Dul(list, i, array[i]);
                    if (InsertStatus == OK) {
                        printf("向双链表第%d个位置插入元素%c成功!\n", i, array[i]);
                    } else {
                        printf("向双链表第%d个位置插入元素%c失败!\n", i, array[i]);
                    }
                }
            }
                break;
            case 9: {//输出链表元素
                printLinkList(list);
            }
                break;
            case 10: {//头插法创建双链表
                //getchar();
                DuLinkList L;
                printf("请输入五个字符:\n");
                CreateDLinkList_H(L, 5);
                int length = GetLinkListLength(L);
                printf("\n循环双链表的长度为:%d。 \n", length);
                printf("循环双链表的元素为:");
                printLinkList(L);
                printf("\n");
            }
                break;
            case 11: {//尾插法创建双链表
                DuLinkList L;
                printf("请输入五个字符:\n");
                CreateDoubleList_R(L, 5);
                int length = GetLinkListLength(L);
                printf("\n循环双链表的长度为:%d。 \n", length);
                printf("循环双链表的元素为:");
                printLinkList(L);
                printf("\n");
            }
                break;
            default: {
                printf("输入错误,无此功能,请检查输入:\n\n");
            }
        }
    }

    return 1;

}

四、运行结果

相关推荐
爱吃生蚝的于勒1 小时前
C语言内存函数
c语言·开发语言·数据结构·c++·学习·算法
失落的香蕉4 小时前
C语言串讲-2之指针和结构体
java·c语言·开发语言
ChoSeitaku7 小时前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表
DdddJMs__1357 小时前
C语言 | Leetcode C语言题解之第557题反转字符串中的单词III
c语言·leetcode·题解
娃娃丢没有坏心思7 小时前
C++20 概念与约束(2)—— 初识概念与约束
c语言·c++·现代c++
workflower8 小时前
数据结构练习题和答案
数据结构·算法·链表·线性回归
一个不喜欢and不会代码的码农8 小时前
力扣105:从先序和中序序列构造二叉树
数据结构·算法·leetcode
ahadee9 小时前
蓝桥杯每日真题 - 第11天
c语言·vscode·算法·蓝桥杯
No0d1es10 小时前
2024年9月青少年软件编程(C语言/C++)等级考试试卷(九级)
c语言·数据结构·c++·算法·青少年编程·电子学会
bingw011410 小时前
华为机试HJ42 学英语
数据结构·算法·华为