一、线性表的分类
线性结构图解
把线性结构类比成一条珍珠项链
每个珠子都是一个数据元素,除去头和尾的珠子,每个都有相邻的珠子。我们把珠子左右的元素分别叫做“前驱”和“后继”,且每个珠子只会存在唯一的“前驱”和“后继”
线性表有个主要的操作特点是可以在任意位置插入和删除一个数据元素。
线性表的类型定义
零个或多个数据元素的有限序列,每个元素的信息可以是任意构成,但在同一个线性表中的元素必定有具有相同特性。
线性表是一个很灵活的数据结构,其长度可以根据需要进行增减。线性表的不仅可以访问元素,还可以进行插入和删除操作。
线性表的基本操作
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;
}