版权声明:Sock的blog, 可以偷看但不可以偷走哦 https://blog.csdn.net/qq_42957923/article/details/84884017
在数据结构中我们经常会用到链表来处理一些问题, 链表同顺序表一样, 包括静态链表和动态链表, 静态链表并不是很常用, 但动态链表的重要性是不言而喻的. 接下来我们看一下动态链表的基本操作, 以书上的资料为参考, 同时自己对动态链表增加了新的认识和总结
动态链表的基本操作
动态链表的定义
//定义一个动态链表
typedef int ElemType;
typedef struct LNode {
ElemType data;
struct LNode* next;
}LNode, *LinkList;
创建一个动态链表
//创建一个动态链表
void CreateList(LinkList* L, int len) {
printf("请输入 %d 个数据:", len);
//创建链表的头节点
*L = (LinkList)malloc(sizeof(LNode));
//定义一个指向尾节点的指针和一个指向创建结点的指针
LinkList rear = *L, p = NULL;
//创建指定大小的空间
for (int i = 1; i < len + 1; ++i) {
p = (LinkList)malloc(sizeof(LNode));
scanf("%d", &p->data);
//尾指针连接新结点
rear->next = p;
//改变尾指针位置
rear = p;
}
//尾指针之后为空
rear->next = NULL;
}
//逆序
//void CreateList(LinkList* L, int len) {
// printf("请输入 %d 个数据:", len);
// //创建头节点
// *L = (LinkList)malloc(sizeof(LNode));
// (*L)->next = NULL;
// //定义一个指向创建结点的指针
// LinkList p = NULL;
// for (int i = 1; i < len; ++i) {
// p = (LinkList)malloc(sizeof(LNode));
// scanf("%d", &p->data);
// p->next = (*L)->next;
// (*L)->next = p;
// }
// printf("\n");
//}
求链表的长度
//链表长度
int Length(LinkList L) {
int len = 0;
while (L->next != NULL) {
++len;
L = L->next;
}
return len;
}
向动态链表中插入结点
//向动态链表中插入结点
void InsertList(LinkList* L, int pos, ElemType e) {
//判断插入位置是否合理
if (pos < 1 || pos > Length(*L) + 1) {
printf("插入位置不合理\n");
return;// exit(0);
}
LinkList adjust = *L;
LinkList insert = (LinkList)malloc(sizeof(LNode));
insert->data = e;
//调整adjust的位置, 准备连接
int i = 0;
while (i++ < pos - 1) {
adjust = adjust->next;
}
//连接右端
insert->next = adjust->next;
//连接左端
adjust->next = insert;
}
从动态链表中删除结点
//从动态链表中删除结点
void DeleteList(LinkList* L, int pos) {
//判断删除结点的位置是否合理
if (pos < 1 || pos > Length(*L)) {
printf("删除结点的位置不合理\n");
return;// exit(0);
}
LinkList adjust = *L;
//调整删除位置, 准备删除指定结点
int i = 0;
while (i++ < pos - 1) {
adjust = adjust->next;
}
//保存要删除的结点
LinkList deleted = adjust->next;
//连接要删除结点的两端结点
adjust->next = deleted->next;
//释放结点
free(deleted);
}
销毁一个动态链表
//销毁一个动态链表
void DestroyList(LinkList* L) {
LinkList adjust = *L;
while (*L) {
//调整指针始终在头节点的下一个位置, 用来保存新的头节点
adjust = (*L)->next;
//释放头节点
free(*L);
//调整新头节点的位置
*L = adjust;
}
printf("链表已销毁\n");
}
清空一个动态链表
//清空一个动态链表
void ClearList(LinkList* L) {
LinkList adjust = (*L)->next;
while ((*L)->next) {
//调整指针始终指向被删除结点的下一个结点, 用来保存下一个要被删除的结点
adjust = adjust->next;
//每次释放头节点的下一个结点
free((*L)->next);
//更新头节点的下一个结点(调整指针指向的结点)
(*L)->next = adjust;
}
printf("链表已清空\n");
}
判断链表是否为空
//判断链表是否为空
int IsEmpty(LinkList L) {
if (L->next == NULL) {
//printf("链表为空\n");
return 1;
}
//printf("链表不为空\n");
return 0;
}
获取动态链表上的某个值
//获取动态链表上某个位置上的值
ElemType GetElem(LinkList L, int pos) {
//判断获取位置是否合理
if (pos < 1 || pos > Length(L)) {
printf("获取位置不合理\n");
return 0;// exit(0);
}
LinkList adjust = L;
//调整获取位置
int i = 0;
while (i++ < pos) {
adjust = adjust->next;
}
//返回获取值
return adjust->data;
}
在动态链表中查找某个元素
//在动态链表中查找某个元素
void LocateElem(LinkList L, ElemType e) {
LinkList adjust = L->next;
int count = 0;
//遍历链表
while (adjust) {
++count;
if (adjust->data == e) {
printf("找到了该元素, 它是第 %d 个元素\n", count);
return;
}
adjust = adjust->next;
}
printf("没有找到该元素\n");
}
在动态链表中查找某个元素的前驱
//在动态链表中查找某个元素的前驱
ElemType ProriElem(LinkList L, ElemType cur_e) {
//判断是否为第一个元素
if (L->next->data == cur_e) {
printf("第一个元素无前驱\n");
return 0;
}
//从第二个元素开始查找
LinkList adjust = L->next;
while (adjust->next) {
if (adjust->next->data == cur_e) {
return adjust->data;
}
adjust = adjust->next;
}
printf("没有该元素\n");
return 0;
}
在动态链表中查找某个元素的后继
//在动态链表中找某个元素的后继
ElemType NextElem(LinkList L, ElemType cur_e) {
//从第一个元素查找, 最后一个元素要进行判断
LinkList adjust = L->next;
while (adjust) {
if (adjust->data == cur_e) {
if (adjust->next != NULL) {
return adjust->next->data;
}
printf("最后一个元素没有后继\n");
return 0;
}
adjust = adjust->next;
}
printf("没有该元素\n");
return 0;
}
遍历链表
//遍历链表
void Traverse(LinkList L) {
//判断链表是否为空
if (L->next == NULL) {
printf("链表为空\n");
return;
}
while (L->next != NULL) {
printf("%d ", L->next->data);
L = L->next;
}
printf("\n");
}
测试
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
//定义一个动态链表
typedef int ElemType;
typedef struct LNode {
ElemType data;
struct LNode* next;
}LNode, *LinkList;
//创建一个动态链表
void CreateList(LinkList* L, int len) {
printf("请输入 %d 个数据:", len);
//创建链表的头节点
*L = (LinkList)malloc(sizeof(LNode));
//定义一个指向尾节点的指针和一个指向创建结点的指针
LinkList rear = *L, p = NULL;
//创建指定大小的空间
for (int i = 1; i < len + 1; ++i) {
p = (LinkList)malloc(sizeof(LNode));
scanf("%d", &p->data);
//尾指针连接新结点
rear->next = p;
//改变尾指针位置
rear = p;
}
//尾指针之后为空
rear->next = NULL;
}
//逆序
//void CreateList(LinkList* L, int len) {
// printf("请输入 %d 个数据:", len);
// //创建头节点
// *L = (LinkList)malloc(sizeof(LNode));
// (*L)->next = NULL;
// //定义一个指向创建结点的指针
// LinkList p = NULL;
// for (int i = 1; i < len; ++i) {
// p = (LinkList)malloc(sizeof(LNode));
// scanf("%d", &p->data);
// p->next = (*L)->next;
// (*L)->next = p;
// }
// printf("\n");
//}
//链表长度
int Length(LinkList L) {
int len = 0;
while (L->next != NULL) {
++len;
L = L->next;
}
return len;
}
//向动态链表中插入结点
void InsertList(LinkList* L, int pos, ElemType e) {
//判断插入位置是否合理
if (pos < 1 || pos > Length(*L) + 1) {
printf("插入位置不合理\n");
return;// exit(0);
}
LinkList adjust = *L;
LinkList insert = (LinkList)malloc(sizeof(LNode));
insert->data = e;
//调整adjust的位置, 准备连接
int i = 0;
while (i++ < pos - 1) {
adjust = adjust->next;
}
//连接右端
insert->next = adjust->next;
//连接左端
adjust->next = insert;
}
//从动态链表中删除结点
void DeleteList(LinkList* L, int pos) {
//判断删除结点的位置是否合理
if (pos < 1 || pos > Length(*L)) {
printf("删除结点的位置不合理\n");
return;// exit(0);
}
LinkList adjust = *L;
//调整删除位置, 准备删除指定结点
int i = 0;
while (i++ < pos - 1) {
adjust = adjust->next;
}
//保存要删除的结点
LinkList deleted = adjust->next;
//连接要删除结点的两端结点
adjust->next = deleted->next;
//释放结点
free(deleted);
}
//销毁一个动态链表
void DestroyList(LinkList* L) {
LinkList adjust = *L;
while (*L) {
//调整指针始终在头节点的下一个位置, 用来保存新的头节点
adjust = (*L)->next;
//释放头节点
free(*L);
//调整新头节点的位置
*L = adjust;
}
printf("链表已销毁\n");
}
//清空一个动态链表
void ClearList(LinkList* L) {
LinkList adjust = (*L)->next;
while ((*L)->next) {
//调整指针始终指向被删除结点的下一个结点, 用来保存下一个要被删除的结点
adjust = adjust->next;
//每次释放头节点的下一个结点
free((*L)->next);
//更新头节点的下一个结点(调整指针指向的结点)
(*L)->next = adjust;
}
printf("链表已清空\n");
}
//判断链表是否为空
int IsEmpty(LinkList L) {
if (L->next == NULL) {
//printf("链表为空\n");
return 1;
}
//printf("链表不为空\n");
return 0;
}
//获取动态链表上某个位置上的值
ElemType GetElem(LinkList L, int pos) {
//判断获取位置是否合理
if (pos < 1 || pos > Length(L)) {
printf("获取位置不合理\n");
return 0;// exit(0);
}
LinkList adjust = L;
//调整获取位置
int i = 0;
while (i++ < pos) {
adjust = adjust->next;
}
//返回获取值
return adjust->data;
}
//在动态链表中查找某个元素
void LocateElem(LinkList L, ElemType e) {
LinkList adjust = L->next;
int count = 0;
//遍历链表
while (adjust) {
++count;
if (adjust->data == e) {
printf("找到了该元素, 它是第 %d 个元素\n", count);
return;
}
adjust = adjust->next;
}
printf("没有找到该元素\n");
}
//在动态链表中查找某个元素的前驱
ElemType ProriElem(LinkList L, ElemType cur_e) {
//判断是否为第一个元素
if (L->next->data == cur_e) {
printf("第一个元素无前驱\n");
return 0;
}
//从第二个元素开始查找
LinkList adjust = L->next;
while (adjust->next) {
if (adjust->next->data == cur_e) {
return adjust->data;
}
adjust = adjust->next;
}
printf("没有该元素\n");
return 0;
}
//在动态链表中找某个元素的后继
ElemType NextElem(LinkList L, ElemType cur_e) {
//从第一个元素查找, 最后一个元素要进行判断
LinkList adjust = L->next;
while (adjust) {
if (adjust->data == cur_e) {
if (adjust->next != NULL) {
return adjust->next->data;
}
printf("最后一个元素没有后继\n");
return 0;
}
adjust = adjust->next;
}
printf("没有该元素\n");
return 0;
}
//遍历链表
void Traverse(LinkList L) {
//判断链表是否为空
if (L->next == NULL) {
printf("链表为空\n");
return;
}
while (L->next != NULL) {
printf("%d ", L->next->data);
L = L->next;
}
printf("\n");
}
int main() {
LinkList L1;
CreateList(&L1, 5);
Traverse(L1);
InsertList(&L1, 4, 100);
Traverse(L1);
int value = GetElem(L1, 4);
printf("%d\n", value);
LocateElem(L1, 100);
int prori_e = ProriElem(L1, 100);
printf("%d\n", prori_e);
int next_e = NextElem(L1, 100);
printf("%d\n", next_e);
DeleteList(&L1, 4);
Traverse(L1);
system("pause");
return 0;
}
效果图
希望能得到大家的指点和支持