0
点赞
收藏
分享

微信扫一扫

循环双链表的简单实现(C语言)

他说Python 2022-03-25 阅读 29

循环双链表的简单实现(C语言)

小结

双链表就像一群人手拉手站成一排,最旁边的两个人都有一个手空着。循环双链表就是一群人手拉手站成一圈,第一个人的手和最后一个人的手互相牵着。
在这里插入图片描述

双链表与循环双链表的插入删除等操作基本一致,表尾判断有所不同。双链表判断表尾为后继指向NULL,循环双链表判断表尾则看其后继是否指向头指针。

插入

结点后插

// 后插结点
bool InsertNextNode(DLNode *p, DLNode *s){
    if(p == NULL && s == NULL)  return true;    // 数据非法性判断
    p->next->prior = s; // p原后继结点的前继指向s
    s->next = p->next;  // s后继结点设为p的原后继结点
    p->next = s;        // p的后继结点设为s
    s->prior = p;       // s的前继结点设为p 
    return true;
}

结点前插

// 前插结点
bool InsertPriorNode(DLNode *p, DLNode *s){     // 在p结点前插入s结点
    if(p == NULL && s == NULL)  return true;    // 数据非法性判断
    s->prior = p->prior;    // s的前继结点设为原p的前继结点
    p->prior->next = s;     // p的前继结点的后继指向s
    s->next = p;            // s的后继结点设为p
    p->prior = s;           // p的前继结点设为s
    return true;
}

尾插法

// 尾插法
DLinkList List_TailInsert(DLinkList L){
    ElemType e;
    DLNode *p = L;           // 声明一个结点,用于定位
    scanf("%d", &e);
    while(e != 9999){
        while(p->next != L){ // 定位至表尾
        p = p->next;
        }
    DLNode *s = (DLNode*)malloc(sizeof(DLNode));    // 声明一个新结点用于插入
    s->data = e;            // 存入数据
    s->next = NULL;
    s->prior = NULL;
    InsertNextNode(p, s);   // 调用后插结点函数实现插入
    scanf("%d", &e);
    }
    return L;
}

头插法

// 头插法
DLinkList List_HeadInsert(DLinkList L){
    ElemType e;
    DLNode *p = L;           // 声明一个结点,用于定位
    scanf("%d", &e);
    while(e != 9999){
        if(p->next == L){   // 第一个结点特殊处理
            DLNode *s = (DLNode*)malloc(sizeof(DLNode));    // 声明一个新结点用于插入
            s->data = e;            // 存入数据
            L->next = s;
            L->prior = s;
            s->next = L;
            s->prior = L;       
        }else{
            DLNode *s = (DLNode*)malloc(sizeof(DLNode));    // 声明一个新结点用于插入
            s->data = e;    // 存入数据
            s->next = NULL;
            s->prior = NULL; 
            InsertPriorNode(L->next, s);    // 调用前插结点函数,在第一个结点进行前插    
        }
    scanf("%d", &e);
    }
    return L;
}

按位插入

// 按位插入
bool ListInsert(DLinkList L, int pos, ElemType e){
    if(L == NULL || pos < 1) return false;
    DLNode *p = L;
    DLNode *s = (DLNode*)malloc(sizeof(DLNode));    // 创建一个新结点用于插入
    s->data = e;
    s->next = NULL;
    s->prior = NULL;
    while(--pos){   // 定位到插入位序的前一个结点
        p = p->next;       
    }
    if(InsertNextNode(p, s)){   //调用结点后插函数进行后插操作
        return true;
    }else false;
}

删除

结点后删

// 后删结点
bool DeleteNextNode(DLNode *p){
    if(p == NULL) return true;  // 数据合法性判断
    DLNode *q = p->next;        // q为将删除的结点
    q->next->prior = p;         // q的后继结点前继指向p
    p->next = q->next;          // p的后继改为q的后继
    free(q);                    // 释放q
    return true;
}

按位删除

// 按位删除
bool ListDelete(DLinkList L, int pos, ElemType *e){
    if(L == NULL || pos < 1) return false;
    DLNode *p = L;
    while(--pos){   // 定位到删除结点的前继结点
        p = p->next;
    }
    *e = p->next->data;     // 通过指针把删除结点的数据域传回主函数
    if(DeleteNextNode(p)){  // 调用结点后删操作进行删除
        return true;
    }else return false;
}

查找

按位查找

// 按位查找
ElemType GetElem(DLinkList L, int pos){
    DLNode *p = L;  // 用于定位
    while(pos){     // pos值每-1移动p一次直到知道位置
        p = p->next;
        pos--;
    }
    return p->data; // 返回查找到的值
}

按值查找

// 按值查找
int LocateElem(DLinkList L, ElemType e){
    int pos = 0;
    DLNode *p = L;
    while(e != p->data){    // 数据域 ==e 时停止
        p = p->next;
        pos++;
    }
    return pos; // 返回查找到的位置
}

其他

定义


typedef int ElemType;
typedef struct DLNode{
    ElemType data;
    struct DLNode *prior,*next; // prior存储前继结点的指针,next存储后继结点的指针
}DLNode, *DLinkList;

初始化

// 初始化
bool InitList(DLinkList *L){
    // 创建空表
    (*L) = (DLNode*)malloc(sizeof(DLNode));
    if(L == NULL) return false;     // 分配失败
    (*L)->next = (*L);
    (*L)->prior = (*L); // 前后结点都指向自己
    return true;
}

求表长

// 求表长
int Length(DLinkList L){
    int len = 0;
    DLNode *p = L;          // 用于定位
    while(p->next != L){    // 遍历链表,到最后一个结点停止
        p = p->next;
        len++;
    }
    return len;
}

表判空

双链表的判空为头结点的后继是否为NULL,而循环双链表的判空是头结点是否指向自己。

// 判空
bool Empty(DLinkList L){
    if(L->next == L){   // 头结点指向自己则为空
        return true;
    }else return false;
}

销毁表

// 销毁表
bool DestoryList(DLinkList *L){
    while((*L)->next != *L){
        DeleteNextNode(*L);
    }
    free(*L);      // 释放头结点
    (*L) = NULL;   // 调用free()后L仍然会指向相同的内存空间,但是此时该内存已无效,不能被使用.故建议将L的值设为NULL
    return true;
}

输出表

// 输出表
void PrintList(DLinkList L){
    DLNode *p = L;
    while(p->next != L){    // 遍历链表逐个输出
        p = p->next;
        printf("%d ", p->data);
    }
    printf("\n");
}

完整代码

// 循环双链表
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>

typedef int ElemType;
typedef struct DLNode{
    ElemType data;
    struct DLNode *prior,*next; // prior存储前继结点的指针,next存储后继结点的指针
}DLNode, *DLinkList;

// 初始化
bool InitList(DLinkList *L){
    // 创建空表
    (*L) = (DLNode*)malloc(sizeof(DLNode));
    if(L == NULL) return false;     // 分配失败
    (*L)->next = (*L);
    (*L)->prior = (*L); // 前后结点都指向自己
    return true;
}

// 后插结点
bool InsertNextNode(DLNode *p, DLNode *s){
    if(p == NULL && s == NULL)  return true;    // 数据非法性判断
    p->next->prior = s; // p原后继结点的前继指向s
    s->next = p->next;  // s后继结点设为p的原后继结点
    p->next = s;        // p的后继结点设为s
    s->prior = p;       // s的前继结点设为p 
    return true;
}

// 前插结点
bool InsertPriorNode(DLNode *p, DLNode *s){     // 在p结点前插入s结点
    if(p == NULL && s == NULL)  return true;    // 数据非法性判断
    s->prior = p->prior;    // s的前继结点设为原p的前继结点
    p->prior->next = s;     // p的前继结点的后继指向s
    s->next = p;            // s的后继结点设为p
    p->prior = s;           // p的前继结点设为s
    return true;
}

// 尾插法
DLinkList List_TailInsert(DLinkList L){
    ElemType e;
    DLNode *p = L;           // 声明一个结点,用于定位
    scanf("%d", &e);
    while(e != 9999){
        while(p->next != L){ // 定位至表尾
        p = p->next;
        }
    DLNode *s = (DLNode*)malloc(sizeof(DLNode));    // 声明一个新结点用于插入
    s->data = e;            // 存入数据
    s->next = NULL;
    s->prior = NULL;
    InsertNextNode(p, s);   // 调用后插结点函数实现插入
    scanf("%d", &e);
    }
    return L;
}

// 头插法
DLinkList List_HeadInsert(DLinkList L){
    ElemType e;
    DLNode *p = L;           // 声明一个结点,用于定位
    scanf("%d", &e);
    while(e != 9999){
        if(p->next == L){   // 第一个结点特殊处理
            DLNode *s = (DLNode*)malloc(sizeof(DLNode));    // 声明一个新结点用于插入
            s->data = e;            // 存入数据
            L->next = s;
            L->prior = s;
            s->next = L;
            s->prior = L;       
        }else{
            DLNode *s = (DLNode*)malloc(sizeof(DLNode));    // 声明一个新结点用于插入
            s->data = e;    // 存入数据
            s->next = NULL;
            s->prior = NULL; 
            InsertPriorNode(L->next, s);    // 调用前插结点函数,在第一个结点进行前插    
        }
    scanf("%d", &e);
    }
    return L;
}

// 按位插入
bool ListInsert(DLinkList L, int pos, ElemType e){
    if(L == NULL || pos < 1) return false;
    DLNode *p = L;
    DLNode *s = (DLNode*)malloc(sizeof(DLNode));    // 创建一个新结点用于插入
    s->data = e;
    s->next = NULL;
    s->prior = NULL;
    while(--pos){   // 定位到插入位序的前一个结点
        p = p->next;       
    }
    if(InsertNextNode(p, s)){   //调用结点后插函数进行后插操作
        return true;
    }else false;
}

// 后删结点
bool DeleteNextNode(DLNode *p){
    if(p == NULL) return true;  // 数据合法性判断
    DLNode *q = p->next;        // q为将删除的结点
    q->next->prior = p;         // q的后继结点前继指向p
    p->next = q->next;          // p的后继改为q的后继
    free(q);                    // 释放q
    return true;
}

// 按位删除
bool ListDelete(DLinkList L, int pos, ElemType *e){
    if(L == NULL || pos < 1) return false;
    DLNode *p = L;
    while(--pos){   // 定位到删除结点的前继结点
        p = p->next;
    }
    *e = p->next->data;     // 通过指针把删除结点的数据域传回主函数
    if(DeleteNextNode(p)){  // 调用结点后删操作进行删除
        return true;
    }else return false;
}

// 按位查找
ElemType GetElem(DLinkList L, int pos){
    DLNode *p = L;  // 用于定位
    while(pos){     // pos值每-1移动p一次直到知道位置
        p = p->next;
        pos--;
    }
    return p->data; // 返回查找到的值
}

// 按值查找
int LocateElem(DLinkList L, ElemType e){
    int pos = 0;
    DLNode *p = L;
    while(e != p->data){    // 数据域 ==e 时停止
        p = p->next;
        pos++;
    }
    return pos; // 返回查找到的位置
}

// 销毁表
bool DestoryList(DLinkList *L){
    while((*L)->next != *L){
        DeleteNextNode(*L);
    }
    free(*L);      // 释放头结点
    (*L) = NULL;   // 调用free()后L仍然会指向相同的内存空间,但是此时该内存已无效,不能被使用.故建议将L的值设为NULL
    return true;
}

// 判空
bool Empty(DLinkList L){
    if(L->next == L){   // 头结点指向自己则为空
        return true;
    }else return false;
}

// 求表长
int Length(DLinkList L){
    int len = 0;
    DLNode *p = L;          // 用于定位
    while(p->next != L){    // 遍历链表,到最后一个结点停止
        p = p->next;
        len++;
    }
    return len;
}

// 输出表
void PrintList(DLinkList L){
    DLNode *p = L;
    while(p->next != L){    // 遍历链表逐个输出
        p = p->next;
        printf("%d ", p->data);
    }
    printf("\n");
}

int main(){
    DLinkList L;    // 声明一个双链表
    ElemType e;     // 元素
    int status;     // 操作码
    int pos;        // 位序
    int len;        // 表长
    InitList(&L);   // 链表的初始化
    while(1){
        printf("Please enter a status code:\n1.List_TailInsert    2.List_HeadInsert    3.GetElem\n");
            printf("4.LocateElem         5.ListDelete         6.ListInsert\n7.Length             8.Empty              9.PrintList\n");
            printf("10.DestoryList       11.InitList          0.Exit\n");
            scanf("%d", &status);
            if(status == 0) break;
            switch (status){
            case 1:     // 尾插法正序创建双链表
                printf("Please enter the DlinkList elements one by one!(end with 9999)\n");
                L = List_TailInsert(L);
                PrintList(L);
                break;
            case 2:     // 头插法逆序创建双链表
                printf("Please enter the DlinkList elements one by one!(end with 9999)\n");
                L = List_HeadInsert(L);
                PrintList(L);
                break;
            case 3:     // 按位查找
                printf("Please enter the position of the node you want to find!\n");
                scanf("%d", &pos);
                e = GetElem(L, pos);
                printf("The value in the %d position is %d\n", pos, e);
                break;
            case 4:     // 按值查找
                printf("Please enter the element value you want to find!\n");
                scanf("%d", &e);
                pos = LocateElem(L, e);
                printf("The address of the linked list where the element with the value %d is located is %d\n", e, pos);
                break;
            case 5:     // 按位删除
                printf("Please enter the position of the node you want to delete!\n");
                scanf("%d", &pos);
                if(ListDelete(L, pos, &e)){
                    printf("Element value %d deleted successfully\n", e);
                    PrintList(L);
                }else{
                    printf("Failed to delete!\n");
                }
                break;
            case 6:     // 按位插入
                printf("Please enter the position and element value you want to insert\n");
                scanf("%d%d", &pos, &e);
                if(ListInsert(L, pos, e)){
                    printf("Inserted successfully\n");
                    PrintList(L);
                }else{
                    printf("Failed to insert!\n");
                }
                break;
            case 7:     // 求表长
                len = Length(L);
                printf("The length of the DLinkList is %d\n", len);
                break;
            case 8:     // 判空
                if(L == NULL){
                    printf("DList not exist!\n");
                }
                else if(Empty(L)){
                    printf("DLinkList is empty!\n");
                }else{
                    printf("DLinkList not empty!\n");
                    PrintList(L);
                }
                break;
            case 9:     // 输出表
                PrintList(L);
                break;
            case 10:    // 销毁表
               if(DestoryList(&L)){
                    printf("DList destroyed successfully\n");
                }else
                    printf("Failed to destroy\n");
                break;
            case 11:    // 初始化
                if(InitList(&L)){
                    printf("DList initialized successfully\n");
                }else
                printf("Failed to initialize!\n");
                break;
            default:
                printf("Error!\n");
                break;
            }
    }
    return 0;
}
举报

相关推荐

0 条评论