数据结构-线性表 C语言代码

 一、线性表的分类

线性结构图解

把线性结构类比成一条珍珠项链

每个珠子都是一个数据元素,除去头和尾的珠子,每个都有相邻的珠子。我们把珠子左右的元素分别叫做“前驱”“后继”,且每个珠子只会存在唯一的“前驱”“后继” 

线性表有个主要的操作特点是可以在任意位置插入和删除一个数据元素。

线性表的类型定义

零个或多个数据元素的有限序列,每个元素的信息可以是任意构成,但在同一个线性表中的元素必定有具有相同特性

线性表是一个很灵活的数据结构,其长度可以根据需要进行增减。线性表的不仅可以访问元素,还可以进行插入删除操作。

线性表的基本操作    

InitList( &L )

操作结果:构造一个空的线性表L

DestroyList( &L )

初始条件:线性表 L 已存在

操作结果:销毁线性表 L

ClearList( &L )

初始条件:线性表 L 已存在

操作结果:将 L 重置为空表

ListEmpty( L )

初始条件:线性表 L 已存在

操作结果:若 L 为空表,则返回TRUE,否则返回FALSE

LIstLength( L )

初始条件:线性表 L 已存在

操作结果:返回L中数据元素个数

GetElem( L, i, &e)

初始条件:线性表 L 已存在,1 ≤ i ≤ ListLength(L)

操作结果:用 e 返回 L 中第 i 个数据元素的值

LocateElem( L, e, compare())

初始条件:线性表 L 已存在,compare() 是数据元素判定函数

操作结果:返回L中第1个元素与e满足关系 compare()的数据元素的位序。若这样的数据元素不存在,则返回值为0

PriorElem( L, cur_e, &pre_e)

初始条件:线性表 L 已存在

操作结果:在若cur_e是 L 的数据元素,且不是第一个,则用 pre_e 返回它的前驱,否则操作失败,pre_e 无定义

NextElem( L,  cur_e, &next_e)

初始条件:线性表 L 已存在

操作结果:在若cur_e是 L 的数据元素,且不是最后一个,则用 next_e 返回它的后继,否则操作失败,next_e 无定义

ListInsert( &L, i, e)

初始条件:线性表 L 已存在,1 ≤ i ≤ ListLength(L) + 1

操作结果:在L中第 i 个位置之前插入新的数据元素 e, L 的长度加 1

ListDelete( &L, i, &e )

初始条件:线性表 L 已存在 且 非空, 1 ≤ i ≤ ListLength(L)

操作结果:删除  L 的第 i 个数据元素,并用 e 返回其值, L 的长度减 1

ListTraverse( L )

初始条件:线性表 L 已存在

操作结果:遍历 线性表 L 

二、顺序存储结构

顺序表

#include <stdio.h>
#include <malloc.h>

#define MaxSize 110 // 数据范围
#define ElemType int

/* -------------------------------- 顺序表 -------------------------------- */
typedef struct
{
    ElemType * data;// 顺序表数据元素
    int length;// 当前有效数据长度
}SqList;

/* -------------------------------- 1. InitList 顺序表的初始化 -------------------------------- */
void InitList(SqList *L)
{
    L->data = (ElemType *)malloc(MaxSize * sizeof(ElemType)); // 为数据元素分配空间
    L->length = 0; // 初始化长度为0

    if (L->data == NULL)
    {
        perror("L->data Memory allocation failed\n");
        exit(1);
    }
    puts("Memory allocation succeed~");
}
/* -------------------------------- 2.DestroyList 销毁 顺序表L  -------------------------------- */
void DestroyList(SqList *L) {
    if (L->data) {
        free(L->data);
        L->data = NULL; // 避免野指针
    }
    L->length = 0;
    puts("DestroyList succeed~");
}

/* -------------------------------- 3. SqListInsert 顺序表的插入 -------------------------------- */

void ListInsert(SqList * L, int i,ElemType e)
{
    // 这里可以写个扩容... 为了方便省略

    if (i < 1 || i > L->length + 1)// 判断元素下标是否越界
    {
        perror("SqListInsert i length exist error");
        exit(1);
    }

    // 从后向前移动元素,为新元素腾出空间
    for (int j = L->length; j >= i; j--) {
        L->data[j] = L->data[j - 1];
    }

    L->data[i - 1] = e; // 插入新元素
    L->length++; // 顺序表长度 +1
    printf("Insert %d position succeed with value %d\n", i, e);
}

/* -------------------------------- 4. GetElem 顺序表的查找 -------------------------------- */
ElemType* GetElem(SqList * L,int i)
{
    if(i < 1 || i > L->length)
    {
        perror("GetElem i length exist error");
        exit(1);
    }
    return &(L->data[i-1]);
}

/* -------------------------------- 5. SqListDelete 顺序表的删除 -------------------------------- */
void ListDelete(SqList * L, int i)
{
    if(i < 1 || i > L->length)
    {
        perror("SqListDelete i length exist error");
        exit(1);
    }

    // 从后向前移动元素,填充空白空间
    for (int j = i - 1; j < L->length - 1; j++) {
        L->data[j] = L->data[j+1];
    }
    L->length--;

    printf("ListDelete succeed with value %d\n", L->data[i - 1]);
}


/* -------------------------------- 6. SqListTraverse 顺序表的遍历 -------------------------------- */
void ListTraverse(SqList * L)
{
    for (int i = 0; i < L->length ; ++i) {
        printf("%d -> ",L->data[i]);
    }
    printf("NULL");
}

/* -------------------------------- 菜单 -------------------------------- */
void menu(SqList * L)
{

    puts("================ 顺序表测试工具 ================");
    puts("1.插入一个新的节点");// ListInsert
    puts("2.销毁当前顺序表");// DestroyList
    puts("3.获取指定位置元素");// DestroyList
    puts("4.删除指定元素");// ListDelete
    puts("5.遍历顺序表");// ListTraverse
    puts("6.初始化顺序表");// InitList
    puts("0.退出");// exit

    int  key = -1;//
    int cnt = 1;// 记录插入的序号
    while(1)
    {
        scanf("%d",&key);
        if(key == 1)
        {
            ElemType e = cnt;
            ListInsert(L,cnt++,e);
        }
        else if(key == 2)
        {
            DestroyList(L);
            cnt = 1;
        }
        else if(key == 3)
        {
            printf("请输入你想要查找的元素位置[提示 当前顺序表长度=%d]: \n",L->length);
            int i;
            scanf("%d",&i);
            ElemType * result = GetElem(L,i);
            printf("L[%d] = %d",i,* result);
        }
        else if(key == 4)
        {
            printf("请输入你想要删除的元素位置[提示 当前顺序表长度=%d]: \n",L->length);
            int i;
            scanf("%d",&i);
            ListDelete(L,i);
        }
        else if(key == 5)
        {
            ListTraverse(L);
        }
        else if(key == 6)
        {
            InitList(L);
        }
        else if(key == 0)
        {
            exit(0);
        } else puts("======== 输入有误请重试 ========");
    }

}

int main() {
    SqList L;
    InitList(&L);// 顺序表初始化
    menu(&L);// 菜单

    return 0;
}

三、链式存储结构

单链表

#include <stdio.h>
#include <malloc.h>

/* --------------------------------  Bool类型定义  -------------------------------- */
typedef int Bool;
#define TRUE 1
#define FALSE 0

/* --------------------------------  数据元素类型定义  -------------------------------- */
typedef struct Node
{
    int val;
    // 待增加若干数据项 item ...
}ElemType;

/* --------------------------------  单链表节点  -------------------------------- */
typedef struct ListNode
{
    ElemType data; // 链表节点包含整个 数据元素
    struct ListNode *  next; // next 指向链表的下一个节点
} ListNode;

/* --------------------------------  初始化一个空的单链表  -------------------------------- */
void InitList(ListNode ** L)
{
    // 判断单链表头结点是否已初始化
    if (*L != NULL) {
        perror("ListNode is already initialized");
        exit(1);
    }

    *L = (ListNode*)malloc(sizeof(ListNode));

    // 判断单链表头结点是否成功分配内存空间
    if (*L == NULL) {
        perror("Memory allocation failed");
        exit(1);
    }

    (*L)->next = NULL; // head 的next 为 NULL
    printf("InitList succeed~\n");
}

/* --------------------------------  销毁 单链表 L  -------------------------------- */
void DestroyList(ListNode ** L)
{

    if(*L != NULL)
    {
        // 销毁所有存在的节点
        ListNode * cur = *L;
        ListNode * ne;
        while(cur != NULL)
        {
            ne = cur->next; // 保存下一个节点的指针
            free(cur); // 释放当前节点内存
            cur = ne;
        }
        *L = NULL; // 避免悬垂指针
    }
    else
    {
        perror("ListNode does not exist");
        exit(1);
    }
    puts("Destroy List succeed~");
}

/* --------------------------------  清空当前 单链表 L  -------------------------------- */
void ClearList(ListNode ** L)
{
    if(*L != NULL)
    {
        // 存在,销毁 并重新分配内存
        DestroyList(L);
        InitList(L);
    }
    else
    {
        perror("ListNode does not exist");
        exit(1);
    }
    puts("Clear List succeed~");
}

/* --------------------------------  判断当前 单链表 是否为空  -------------------------------- */
Bool ListEmpty(ListNode ** L)
{

    // 判断当前链表是否存在
    if(*L == NULL)
    {
        perror("ListNode does not exist");
        exit(1);
    }

    // 判断当前链表是否为空表
    if((*L)->next == NULL)return TRUE;
    return FALSE;
}

/* --------------------------------  返回 单链表 长度 -------------------------------- */
/* 这里可以使用全局变量进行优化实时更改和获取 (为了可读性这里选择了遍历写法) */
int ListLength(ListNode ** L)
{
    int cnt = 0;
    ListNode * cur = (*L)->next;
    while(cur != NULL)
    {
        cur = cur->next;
        cnt++;
    }
    return cnt;
}

/* --------------------------------  获取 单链表 中第i个元素的值  -------------------------------- */
ListNode GetElem(ListNode ** L,int i)
{
    if(i > ListLength(L))
    {
        perror("i > ListLength");
        exit(1);
    }

    ListNode * cur = *L;

    for (int j = 0; j < i; ++j)  cur = cur->next;// 遍历

    return *cur;// 返回元素的"值"
}

/* --------------------------------  获取 单链表中 第1个与 e满足关系的位置。不存在返回 0  -------------------------------- */

int LocateElem(ListNode ** L,ElemType e)
{
     ListNode * cur = (*L)->next;
     int cnt = 0;
     while(cur && cur->data.val != e.val)
     {
         cur = cur->next;
         cnt++;
     }
    if(cur) return cnt;
    else return 0;
}

/* --------------------------------  获取 单链表 当前节点的下一个节点  -------------------------------- */
ListNode * NextElem(ListNode * cur)
{
    return cur->next;
}

/* --------------------------------  向 单链表 i位置插入一个节点 e  -------------------------------- */
void ListInsert(ListNode **L, int i, ElemType e) {
    if (i < 1 || i > ListLength(L) + 1) {
        perror("Insert error ~ The data range of i is incorrect");
        exit(1);
    }
    ListNode *cur = *L;
    for (int j = 0; j < i - 1; ++j) {
        cur = cur->next;
    }
    ListNode *newNode = (ListNode *)malloc(sizeof(ListNode));
    if (!newNode) {
        perror("Memory allocation failed");
        exit(1);
    }
    newNode->data = e;  // 直接使用传入的 e 值
    newNode->next = cur->next;
    cur->next = newNode;
    printf("Insert %d position succeed with value %d\n", i, e.val);
}

/* --------------------------------  删除 单链表 i位置的节点 用e返回其值  -------------------------------- */
void ListDelete(ListNode ** L,int i,ElemType ** e)
{
    ListNode * cur =  *L;
    for (int j = 0; j < i - 1; ++j) cur = cur->next;

    *e = &(cur->next->data);
    cur->next = cur->next->next;
    printf("Delete %d position succeed with value %d\n", i, (*e)->val);
}

/* --------------------------------  遍历单链表 -------------------------------- */
void ListTraverse(ListNode ** L)
{
    ListNode * cur = (*L)->next;
    while(cur != NULL)
    {
        printf("%d --> ",cur->data.val);
        cur = cur->next;
    }
    printf("NULL");
}

/* --------------------------------  菜单 -------------------------------- */
//用于测试单链表的的一些操作

void menu(ListNode * head)
{
    puts("================ 单链表测试工具 ================");
    puts("1.插入一个新的节点");// ListInsert
    puts("2.销毁当前链表");// DestroyList
    puts("3.清空当前链表");// ClearList
    puts("4.删除指定元素");// ListDelete
    puts("5.遍历链表");// ListTraverse
    puts("6.初始化链表");// InitList
    puts("0.退出");// exit

    // 为了方便这里插入操作,默认顺序添加
    int cnt = 1;

    while (1)
    {
        int key = -1;
        scanf("%d",&key);

        int i; // 位置编号

        ElemType elem;
        elem.val = cnt;
        switch (key)
        {
            case 0:
                DestroyList(&head);
                puts("安全退出~");
                exit(0);
            case 1:
                ListInsert(&head,cnt++,elem);
                break;
            case 2:
                DestroyList(&head);
                break;
            case 3:
                ClearList(&head);
                break;
            case 4:
                printf("请输入待删除元素的位置: \n");
                scanf("%d",&i);
                ElemType * deleteElem = (ElemType* ) malloc(sizeof(ElemType));
                ListDelete(&head,i,&deleteElem);
                break;
            case 5:
                ListTraverse(&head);
                break;
            case 6:
                InitList(&head);
                cnt = 1;
                break;

            default:
                puts("======== 输入有误请重试 ========");
        }
    }
}

int main() {

    // head是单链表的头指针
    ListNode * head = NULL;
    // 链表头结点初始化
    InitList(&head);
    // 打开菜单
    menu(head);

    return 0;
}

双向链表

#include <stdio.h>
#include <malloc.h>

/* --------------------------------  Bool类型定义  -------------------------------- */
typedef int Bool;
#define TRUE 1
#define FALSE 0

/* --------------------------------  数据元素类型定义  -------------------------------- */
typedef struct Node
{
    int val;
    // 待增加若干数据项 item ...
}ElemType;

/* --------------------------------  双链表链表节点  -------------------------------- */
typedef struct DoubleListNode
{
    ElemType data; // 链表节点包含整个 数据元素
    struct DoubleListNode *  prior; // prior 指向链表的上一个节点
    struct DoubleListNode *  next; // next 指向链表的下一个节点
} DoubleListNode;

/* --------------------------------  1.InitList 初始化一个空的双链表  -------------------------------- */
void InitList(DoubleListNode ** L)
{
    // 检查链表是否存在
    if (*L != NULL) {
        perror(" DoubleListNode is already initialized");
        exit(1);
    }
    *L = (DoubleListNode*)malloc(sizeof(DoubleListNode));

    // 判断头结点是否成功分配内存空间
    if (*L == NULL) {
        perror("Memory allocation failed");
        exit(1);
    }

    (*L)->prior = NULL; // head 的prior 为 NULL
    (*L)->next = NULL; // head 的next 为 NULL

    printf("InitList succeed~\n");
}

/* -------------------------------- 2.DestroyList 销毁 双链表 L  -------------------------------- */
void DestroyList(DoubleListNode ** L)
{
    if(*L != NULL)
    {
        // 销毁所有存在的节点
        DoubleListNode * cur = *L;
        DoubleListNode * ne;
        while(cur != NULL)
        {
            ne = cur->next; // 保存下一个节点的指针
            free(cur); // 释放当前节点内存
            cur = ne;
        }
        *L = NULL; // 避免悬垂指针
    }
    else
    {
        perror("DoubleListNode does not exist");
        exit(1);
    }
    puts("Destroy List succeed~");
}

/* --------------------------------  3.ClearList 清空当前 双链表 L  -------------------------------- */
void ClearList(DoubleListNode ** L)
{
    if(*L != NULL)
    {
        // 存在,销毁 并重新分配内存
        DestroyList(L);
        InitList(L);
    }
    else
    {
        perror("ListNode does not exist");
        exit(1);
    }
    puts("Clear List succeed~");
}

/* --------------------------------  4.ListEmpty 判断当前 双链表 是否为空  -------------------------------- */
Bool ListEmpty(DoubleListNode ** L)
{
    if(*L == NULL)
    {
        perror("The DoubleListNode does not exist");
        exit(1);
    }

    // 判断链表是否为空
    if((*L)->next == NULL) return TRUE;
    return FALSE;
}

/* --------------------------------  5.ListLength 返回 双链表 长度 -------------------------------- */
/* 这里可以使用全局变量进行优化实时更改和获取 (为了可读性这里选择了遍历写法) */
int ListLength(DoubleListNode ** L)
{
    // 链表长度初始为 0
    int len = 0;

    DoubleListNode * cur = (*L)->next;

    while(cur != NULL)
    {
        cur = cur->next;
        len++;
    }
    return len;
}

/* --------------------------------  6.GetElem 获取 双链表 中第i个元素的值  -------------------------------- */
DoubleListNode GetElem(DoubleListNode ** L,int i)
{
    if(i > ListLength(L))
    {
        perror("i > ListLength");
        exit(1);
    }
    DoubleListNode * cur = *L;

    for (int j = 0; j < i; ++j)  cur = cur->next;// 遍历

    return *cur;// 返回元素的"值"
}

/* --------------------------------  7.LocateElem 获取 双链表中 第1个与 e满足关系的位置。不存在返回 0  -------------------------------- */

int LocateElem(DoubleListNode ** L,ElemType e)
{
    DoubleListNode * cur = (*L)->next;
    int cnt = 0;
    while(cur != NULL && cur->data.val != e.val)
    {
        cur = cur->next;
        cnt++;
    }
    if(cur != NULL) return cnt;
    else return 0;
}
/* --------------------------------  9.PriorElem 获取双链表当前节点的前驱  -------------------------------- */
DoubleListNode * PriorElem(DoubleListNode * cur)
{
    return cur->prior;
}

/* --------------------------------  10.NextElem 获取双链表当前节点的后继  -------------------------------- */
    DoubleListNode * NextElem(DoubleListNode * cur)
{
    return cur->next;
}

/* --------------------------------  10.ListInsert 向 双链表 i位置插入一个节点 e  -------------------------------- */
void ListInsert(DoubleListNode ** L, int i, ElemType e) {
    if (i < 1 || i > ListLength(L) + 1) {
        perror("Insert error ~ The data range of i is incorrect");
        exit(1);
    }
    DoubleListNode * cur = *L;
    // 找到插入位置的上一个节点
    for (int j = 0; j < i - 1; ++j) {
        cur = cur->next;
    }
    DoubleListNode * newNode = (DoubleListNode *)malloc(sizeof(DoubleListNode));
    if (!newNode) {
        perror("Memory allocation failed");
        exit(1);
    }

    newNode->data = e;// 直接使用传入的 e 值
    newNode->next = cur->next;
    cur->next = newNode;
    newNode->prior = cur;
    printf("Insert %d position succeed with value %d\n", i, e.val);
}

/* --------------------------------  11.ListDelete 删除 双链表 i位置的节点 用e返回其值  -------------------------------- */
void ListDelete(DoubleListNode ** L,int i,ElemType ** e)
{
    if (i < 1 || i > ListLength(L)) {
        perror("Delete error ~ The data range of i is incorrect");
        exit(1);
    }
    DoubleListNode * cur =  *L;
    for (int j = 0; j < i - 1; ++j) cur = cur->next;

    *e = &(cur->next->data);// 把删除的元素传回去

    // 更新前驱节点
    cur->next->next->prior = cur;

    // 释放内存
    free(cur->next);

    // 更新后继节点
    cur->next = cur->next->next;

    printf("Delete %d position succeed with value %d\n", i, (*e)->val);
}

/* -------------------------------- 12.ListTraverse 遍历单链表 -------------------------------- */
void ListTraverseA(DoubleListNode ** L)
{
    DoubleListNode * cur = (*L)->next;
    while(cur != NULL)
    {
        printf("%d --> ",cur->data.val);
        cur = cur->next;
    }
    printf("NULL");
}

void ListTraverseB(DoubleListNode ** L)
{
    DoubleListNode * cur = (*L)->next;
    while(cur->next != NULL)cur = cur->next;

    while(cur != *L)
    {
        printf("%d --> ",cur->data.val);
        cur = cur->prior;
    }
    printf("NULL");
}

/* --------------------------------  菜单 -------------------------------- */
//用于测试双链表的的一些操作

void menu(DoubleListNode * head)
{
    puts("================ 双链表测试工具 ================");
    puts("1.插入一个新的节点");// ListInsert
    puts("2.销毁当前链表");// DestroyList
    puts("3.清空当前链表");// ClearList
    puts("4.删除指定元素");// ListDelete
    puts("5.正向遍历链表");// ListTraverseA
    puts("6.逆向遍历链表");// ListTraverseB
    puts("7.初始化链表");// InitList
    puts("0.退出");// exit


    int cnt = 1;// 链表的初始序号从1开始
    while (1)
    {
        int key = -1;
        int i;// 输入的所在位置
        ElemType elem;// 待插入的元素

        scanf("%d",&key);

        switch (key)
        {
            case 0:
                DestroyList(&head);
                cnt = 1;// 重置链表序号
                puts("安全退出~");
                exit(0);
            case 1:
                elem.val = cnt;
                ListInsert(&head,cnt++,elem);
                break;
            case 2:
                DestroyList(&head);
                break;
            case 3:
                ClearList(&head);
                break;
            case 4:
                printf("请输入待删除元素的位置: \n");
                scanf("%d",&i);
                ElemType * deleteElem = (ElemType* ) malloc(sizeof(ElemType));
                ListDelete(&head,i,&deleteElem);
                break;
            case 5:
                ListTraverseA(&head);
                break;
            case 6:
                ListTraverseB(&head);
                break;
            case 7:
                InitList(&head);
                cnt = 1;
                break;

            default:
                puts("======== 输入有误请重试 ========");
        }
    }
}

int main() {

    // head是链表的头指针
    DoubleListNode * head = NULL;
    // 链表头结点初始化
    InitList(&head);
    // 打开菜单
    menu(head);

    return 0;
}

双向循环链表

#include <stdio.h>
#include <malloc.h>

/* --------------------------------  Bool类型定义  -------------------------------- */
typedef int Bool;
#define TRUE 1
#define FALSE 0

/* --------------------------------  数据元素类型定义  -------------------------------- */
typedef struct Node
{
    int val;
    // 待增加若干数据项 item ...
}ElemType;

/* --------------------------------  双向循环链表节点  -------------------------------- */
typedef struct DoubleCirList
{
    ElemType data; // 链表节点包含整个 数据元素
    struct DoubleCirList *  prior; // prior 指向链表的上一个节点
    struct DoubleCirList *  next; // next 指向链表的下一个节点

} DoubleCirList;

/* --------------------------------  1.InitList 初始化一个空的双向循环链表  -------------------------------- */
void InitList(DoubleCirList ** L)
{
    // 检查链表是否存在
    if (*L != NULL) {
        perror(" DoubleCirList is already initialized");
        exit(1);
    }
    *L = (DoubleCirList*)malloc(sizeof(DoubleCirList));

    // 判断头结点是否成功分配内存空间
    if (*L == NULL) {
        perror("Memory allocation failed");
        exit(1);
    }

    (*L)->prior = *L;// 前驱指向 头结点
    (*L)->next = *L; // 后继指向 头结点

    printf("InitList succeed~\n");
}

/* -------------------------------- 2.DestroyList 销毁 双向循环链表 L  -------------------------------- */
Bool ListEmpty(DoubleCirList ** L);

void DestroyList(DoubleCirList ** L)
{
    if(*L != NULL)
    {
        // 销毁所有存在的节点
        DoubleCirList * cur = *L;
        DoubleCirList * ne;
        while(!ListEmpty(&cur))
        {
            ne = cur->next; // 保存下一个节点的指针
            free(cur); // 释放当前节点内存
            cur = ne;
        }
        *L = NULL; // 避免悬垂指针
    }
    else
    {
        perror("DoubleCirList does not exist");
        exit(1);
    }
    puts("Destroy List succeed~");
}

/* --------------------------------  3.ClearList 清空当前 双向循环链表 L  -------------------------------- */
void ClearList(DoubleCirList ** L)
{
    if(*L != NULL)
    {
        // 存在,销毁 并重新分配内存
        DestroyList(L);
        InitList(L);
    }
    else
    {
        perror("ListNode does not exist");
        exit(1);
    }
    puts("Clear List succeed~");
}

/* --------------------------------  4.ListEmpty 判断当前 双向循环链表 是否为空  -------------------------------- */
Bool ListEmpty(DoubleCirList ** L)
{
    if(*L == NULL)
    {
        perror("The DoubleCirList does not exist");
        exit(1);
    }

    // 判断链表是否为空
    if((*L)->next == (*L)->prior)return TRUE;
    return FALSE;

}

/* --------------------------------  5.ListLength 返回 双向循环链表 长度 -------------------------------- */
/* 这里可以使用全局变量进行优化实时更改和获取 (为了可读性这里选择了遍历写法) */
int ListLength(DoubleCirList ** L)
{
    // 链表长度初始为 0
    int len = 0;
    DoubleCirList * cur = (*L)->next;
    while (cur != *L)
    {
        cur = cur->next;
        len++;
    }
    return len;
}

/* --------------------------------  6.GetElem 获取 双向循环链表 中第i个元素的值  -------------------------------- */
DoubleCirList GetElem(DoubleCirList ** L,int i)
{
    if(i > ListLength(L))
    {
        perror("i > ListLength");
        exit(1);
    }
    DoubleCirList * cur = *L;

    for (int j = 0; j < i; ++j)  cur = cur->next;// 遍历

    return *cur;// 返回元素的"值"
}

/* --------------------------------  7.LocateElem 获取 双向循环链表中 第1个与 e满足关系的位置。不存在返回 0  -------------------------------- */

int LocateElem(DoubleCirList ** L,ElemType e)
{
    DoubleCirList * cur = (*L)->next;
    int cnt = 0;
    while(cur->prior != cur->next && cur->data.val != e.val)
    {
        cur = cur->next;
        cnt++;
    }
    if(cur->prior != cur->next ) return cnt;
    else return 0;
}
/* --------------------------------  9.PriorElem 获取双向循环链表当前节点的前驱  -------------------------------- */
DoubleCirList * PriorElem(DoubleCirList * cur)
{
    return cur->prior;
}

/* --------------------------------  10.NextElem 获取双向循环链表当前节点的后继  -------------------------------- */
DoubleCirList * NextElem(DoubleCirList * cur)
{
    return cur->next;
}

/* --------------------------------  10.ListInsert 向 双向循环链表 i位置插入一个节点 e  -------------------------------- */
void ListInsert(DoubleCirList ** L, int i, ElemType e) {

    if (i < 1 || i > ListLength(L) + 1) {
        perror("Insert error ~ The data range of i is incorrect");
        exit(1);
    }
    DoubleCirList * cur = *L;
    // 找到插入位置的上一个节点
    for (int j = 0; j < i - 1; ++j) cur = cur->next;

    DoubleCirList * newNode = (DoubleCirList *)malloc(sizeof(DoubleCirList));

    if (!newNode) {
        perror("Memory allocation failed");
        exit(1);
    }

    newNode->data = e;// 直接使用传入的 e 值

    cur->next->prior = newNode; // 更新 cur->next 的前驱
    newNode->next = cur->next;// 更新 newNode 的后继
    cur->next = newNode;// 更新 cur 的后继
    newNode->prior = cur;// 更新newNode 的前驱

    printf("Insert %d position succeed with value %d\n", i, e.val);
}

/* --------------------------------  11.ListDelete 删除 双向循环链表 i位置的节点 用e返回其值  -------------------------------- */
void ListDelete(DoubleCirList ** L,int i,ElemType ** e)
{
    if (i < 1 || i > ListLength(L)) {
        perror("Delete error ~ The data range of i is incorrect");
        exit(1);
    }
    DoubleCirList * cur =  *L;
    for (int j = 0; j < i - 1; ++j) cur = cur->next;

    *e = &(cur->next->data);// 把删除的元素传回去

    // 更新前驱节点
    cur->next->next->prior = cur;

    // 释放内存
    free(cur->next);

    // 更新后继节点
    cur->next = cur->next->next;
    printf("Delete %d position succeed with value %d\n", i, (*e)->val);
}

/* -------------------------------- 12.ListTraverse 遍历单链表 -------------------------------- */
void ListTraverseA(DoubleCirList ** L)
{
    DoubleCirList * cur = (*L)->next;
    while(cur != *L)
    {
        printf("%d --> ",cur->data.val);
        cur = cur->next;
    }
    printf("NULL");
}
void ListTraverseB(DoubleCirList ** L)
{
    DoubleCirList * cur =  (*L)->prior;

    while(cur != *L)
    {
        printf("%d --> ",cur->data.val);
        cur = cur->prior;
    }
    printf("NULL");
}
/* --------------------------------  菜单 -------------------------------- */
//用于测试双链表的的一些操作

void menu(DoubleCirList * head)
{
    puts("================ 双向循环链表测试工具 ================");
    puts("1.插入一个新的节点");// ListInsert
    puts("2.销毁当前链表");// DestroyList
    puts("3.清空当前链表");// ClearList
    puts("4.删除指定元素");// ListDelete
    puts("5.正向遍历链表");// ListTraverseA
    puts("6.逆向遍历链表");// ListTraverseB
    puts("7.初始化链表");// InitList
    puts("0.退出");// exit


    int cnt = 1;// 链表的初始序号从1开始
    while (1)
    {
        int key = -1;
        int i;// 输入的所在位置
        ElemType elem;// 待插入的元素

        scanf("%d",&key);

        switch (key)
        {
            case 0:
                DestroyList(&head);
                cnt = 1;// 重置链表序号
                puts("安全退出~");
                exit(0);
            case 1:
                elem.val = cnt;
                ListInsert(&head,cnt++,elem);
                break;
            case 2:
                DestroyList(&head);
                break;
            case 3:
                ClearList(&head);
                break;
            case 4:
                printf("请输入待删除元素的位置: \n");
                scanf("%d",&i);
                ElemType * deleteElem = (ElemType* ) malloc(sizeof(ElemType));
                ListDelete(&head,i,&deleteElem);
                break;
            case 5:
                ListTraverseA(&head);
                break;
            case 6:
                ListTraverseB(&head);
                break;
            case 7:
                InitList(&head);
                cnt = 1;
                break;

            default:
                puts("======== 输入有误请重试 ========");
        }
    }
}

int main() {

    // head是链表的头指针
    DoubleCirList * head = NULL;
    // 链表头结点初始化
    InitList(&head);
    // 打开菜单
    menu(head);

    return 0;
}

  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值