链表(单向链表、双向链表、循环链表)
文章目录
本文将详细展示单向链表、双向链表、循环链表的构造以及最基本的增删改查。
1.单向链表
1.1单链表的定义
单向链表的每个节点包含一个数据字段和一个指向下一个节点的指针。
typedef int ElemType; // 定义元素类型为int
typedef struct LNode {
ElemType data; // 节点存储数据
struct LNode *next; // 指向下一个节点的指针
} LNode, *LinkList; // 定义LNode结构体和LinkList指针类型
这是一个定义链表的数据结构。链表的节点 LNode
包含两个部分:一个用于存储数据的数组 data[Max_Size]
,以及一个指向下一个节点的指针 next
。
1.2 链表的初始化与销毁
链表的初始化
//链表的初始化
void InitList(LinkList L) {
L = (LinkList) malloc(sizeof(LinkList));
//next结点置空
L->next = NULL;
}
InitList
函数现在接受一个指向链表头指针的指针,分配内存,并初始化 next
指针将其置空。
销毁链表
void DestroyList(LinkList L) {
LinkList p;
LinkList q;
p = L; // p 指向头结点
while (p != NULL) {
q = p;
p = p->next; // 移动 p 到下一个节点
free(q); // 释放当前节点 q 的内存
}
L = NULL; // 将头指针设置为 NULL}
1.3链表的其创建
头插法
//头插法创建链表
void CreateListF(LinkList L,ElemType e[],int n) {
LinkList s;
for (int i = 0; i < n; ++i) {
s = (LinkList)malloc(sizeof(LNode));
s->data = e[i];
s->next = L->next;
L->next = s;
}
}
尾插法
// 尾插法创建链表
void CreateListR(LinkList L, ElemType e[], int n) {
LinkList s, r;
r = L; // 初始化r指针指向头结点
for (int i = 0; i < n; ++i) {
s = (LinkList)malloc(sizeof(LNode)); // 为新节点分配内存
s->data = e[i]; // 将数据赋值给新节点
s->next = NULL; // 新节点的next指针初始化为NULL
r->next = s; // 将新节点链接到链表的尾部
r = s; // 更新r指针到新的尾部节点
}
}
1.4链表的插入
//在第i个位置插入元素e
void Insert(LinkList L,int i,ElemType e) {
int j = 0;
LinkList s = (LinkList)malloc(sizeof(LNode));
LinkList p = L;
//遍历链表
while (j < i - 1 && p != NULL) {
p = p->next;
j++;
}
//执行插入操作
s->data = e;
s->next = p->next;
p->next = s;
}
1.5链表的删除
//删除第i个位置的元素
void Delete(LinkList L,int i) {
int j = 0;
LinkList p = L;
LinkList q = NULL;
//遍历链表
while (j < i - 1 && p != NULL) {
p = p->next;
j++;
}
q = p->next ;
p->next = q->next;
free(q);
}
1.6链表的查找
//查找第i个位置的元素
ElemType Find(LinkList L,int i) {
int j = 0;
LinkList p = L;
//遍历链表
while (j < i - 1 && p != NULL) {
p = p->next;
j++;
}
if(p == NULL) {
return -1;
}
return p->data;
}
2. 双向链表
双向链表的每个节点包含三个部分:一个用于存储数据的 data
,一个指向前一个节点的指针 prev
,以及一个指向后一个节点的指针 next
。
2.1 双向链表的定义
typedef int ElemType; // 定义元素类型为int
typedef struct DNode {
ElemType data; // 节点存储数据
struct DNode *prev; // 指向前一个节点的指针
struct DNode *next; // 指向下一个节点的指针
} DNode, *DLinkList; // 定义DNode结构体和DLinkList指针类型
2.2 链表的初始化与销毁
双向链表的初始化
// 双向链表的初始化
void InitDList(DLinkList L) {
L = (DLinkList) malloc(sizeof(DLinkList));
L->prev = NULL; // prev指针置空
L->next = NULL; // next指针置空
}
销毁双向链表
void DestroyDList(DLinkList L) {
DLinkList p = L;
DLinkList q;
while (p != NULL) {
q = p;
p = p->next;
free(q);
}
L = NULL;
}
2.3 双向链表的创建
头插法
// 头插法创建双向链表
void CreateDListF(DLinkList L, ElemType e[], int n) {
DLinkList s;
for (int i = 0; i < n; ++i) {
s = (DLinkList)malloc(sizeof(DNode));
s->data = e[i];
s->next = L->next;
s->prev = L;
if (L->next != NULL) {
L->next->prev = s;
}
L->next = s;
}
}
尾插法
// 尾插法创建双向链表
void CreateDListR(DLinkList L, ElemType e[], int n) {
DLinkList s, r;
r = L; // r指向尾部节点
while (r->next != NULL) {
r = r->next;
}
for (int i = 0; i < n; ++i) {
s = (DLinkList)malloc(sizeof(DNode));
s->data = e[i];
s->next = NULL;
s->prev = r;
r->next = s;
r = s;
}
}
2.4 双向链表的插入
// 在第i个位置插入元素e
void InsertDList(DLinkList L, int i, ElemType e) {
int j = 0;
DLinkList p = L;
DLinkList s = (DLinkList)malloc(sizeof(DNode));
while (j < i - 1 && p != NULL) {
p = p->next;
j++;
}
s->data = e;
s->next = p->next;
if (p->next != NULL) {
p->next->prev = s;
}
s->prev = p;
p->next = s;
}
2.5 双向链表的删除
// 删除第i个位置的元素
void DeleteDList(DLinkList L, int i) {
int j = 0;
DLinkList p = L;
while (j < i - 1 && p != NULL) {
p = p->next;
j++;
}
DLinkList q = p->next;
if (q != NULL) {
p->next = q->next;
if (q->next != NULL) {
q->next->prev = p;
}
free(q);
}
}
2.6 双向链表的查找
// 查找第i个位置的元素
ElemType FindDList(DLinkList L, int i) {
int j = 0;
DLinkList p = L;
while (j < i - 1 && p != NULL) {
p = p->next;
j++;
}
if (p == NULL) {
return -1;
}
return p->data;
}
3. 循环链表
循环链表与单链表的区别在于其尾节点的 next
指针指向链表的头节点,使得整个链表形成一个环。
3.1 循环链表的定义
typedef int ElemType; // 定义元素类型为int
typedef struct CNode {
ElemType data; // 节点存储数据
struct CNode *next; // 指向下一个节点的指针
} CNode, *CLinkList; // 定义CNode结构体和CLinkList指针类型
3.2 循环链表的初始化与销毁
循环链表的初始化
// 循环链表的初始化
void InitCList(CLinkList L) {
L = (CLinkList) malloc(sizeof(CLinkList));
L->next = L; // 循环链表的next指针指向自己
}
销毁循环链表
void DestroyCList(CLinkList L) {
CLinkList p = L->next;
CLinkList q;
while (p != L) {
q = p;
p = p->next;
free(q);
}
free(L);
}
3.3 循环链表的创建
头插法
// 头插法创建循环链表
void CreateCListF(CLinkList L, ElemType e[], int n) {
CLinkList s;
for (int i = 0; i < n; ++i) {
s = (CLinkList)malloc(sizeof(CNode));
s->data = e[i];
s->next = L->next;
L->next = s;
}
s->next = L; // 形成循环
}
尾插法
// 尾插法创建循环链表
void CreateCListR(CLinkList L, ElemType e[], int n) {
CLinkList s, r;
r = L;
while (r->next != L) {
r = r->next
}
for (int i = 0; i < n; ++i) {
s = (CLinkList)malloc(sizeof(CNode));
s->data = e[i];
s->next = L; // 新节点的next指向头节点,形成环
r->next = s;
r = s;
}
}
3.4 循环链表的插入
// 在第i个位置插入元素e
void InsertCList(CLinkList L, int i, ElemType e) {
int j = 0;
CLinkList p = L;
CLinkList s = (CLinkList)malloc(sizeof(CNode));
while (j < i - 1 && p->next != L) {
p = p->next;
j++;
}
s->data = e;
snext = p->next;
p->next = s;
}
3.5 循环链表的删除
// 删除第i个位置的元素
void DeleteCList(CLinkList L, int i) {
int j = 0;
CLinkList p = L;
while (j < i - 1 && p->next != L)
p = p->next;
j++;
}
CLinkList q = p->next;
if (q != L) {
p->next = q->next;
free(q);
}
}
3.6 循环链表的查找
// 查找第i位置的元素
ElemType FindCList(CLinkList L, int i) {
int j = 0;
CLinkList p = L->next;
while (j < i - 1 && p != L) {
p = p->next;
j++;
}
if (p == L) {
return -1;
}
return p->data;
}
以上是链表的一些基本操作,原版代码上传至(https://gitee.com/shi-chengfu)
如果有错误请联系QQ:303613518