欢迎光临散文网 会员登陆 & 注册

《数据结构(C语言版)》动态单链表的实现

2022-03-25 11:58 作者:回到唐朝当少爷  | 我要投稿

清华大学计算机系列教材   累计发行超400万册

严蔚敏 吴伟明 编著

数据结构(C语言版)

以下是本人对该紫皮书第二章线性表中动态单链表的代码实现,函数部分与课本基本相同,并额外补充了一点代码

(貌似专栏把我缩进吃了,懒得加了,建议用visual studio编译)

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <stdlib.h>

#define TRUE 1

#define FALSE 0

#define OK 1

#define ERROR 0

#define INFEASIBLE -1

#define OVERFLOW -2

typedef int ElemType;

typedef int Status;

typedef struct LNode

{

ElemType data;

struct LNode* next;

}LNode, * LinkList;

/*

关于一个带*号一个不带的解释:

typedef struct LNode LNode;         //将结构体类型struct LNode重命名为LNode

typedef struct LNode *LinkList;     //将struct LNode *重命名为LinkList

LinkList L;    //等价于 struct LNode * L

可以理解为,通过typedef,将struct LNode *替换为LinkList,当我们在使用LinkList L定义变量时,

实际上就是在使用 struct LNode * L定义变量。使得以后想定义指向struct LNode类型的指针变量时,

不需要写struct LNode * ,只需要使用LinkList,减少了代码的书写。

*/

/*

重要操作:

p = L;      //p指向头结点

s = L->next; //s指向首元结点

p = p->next; //p指向下一结点

*/

Status InitList(LinkList& L);//链表初始化

Status ListInsert_L(LinkList& L, int i, ElemType e);//在第i个位置之前插入元素e

int ListEmpty(LinkList L);//判断链表是否为空

int ListLength_L(LinkList L);//求线性表表长

Status GetElem_L(LinkList L, int i, ElemType& e);//按位查找第i个元素是什么

int LocateElem_L_Value(LinkList L, ElemType e);//按值查找值为e的元素并返回其位置

void Output(LinkList L);//打印线性链表中所有元素

Status ListDelete_L(LinkList& L, int i, ElemType& e);//删除第i个元素并由e返回其值

Status ClearList(LinkList& L);//清空单链表

Status DestoryList_L(LinkList& L);//销毁单链表

void CreatList_H(LinkList& L, int n);//用头插法快速建立链表

void CreatList_R(LinkList& L, int n);//尾插法快速建立链表

void MergeList_L(LinkList& La, LinkList& Lb, LinkList& Lc);//已知单链线性表La和Lb的元素按值递增排列,归并得递增排列的Lc

void Menu()

{

printf("***************************\n");

printf("********开 始 菜 单********\n");

printf("********0:退出系统********\n");

printf("********1:插入元素********\n");

printf("********2:判断空表********\n");

printf("********3:计算表长********\n");

printf("********4:按位查找********\n");

printf("********5:按值查找********\n");

printf("********6:打印表单********\n");

printf("********7:删除元素********\n");

printf("********8:清空链表********\n");

printf("********9:销毁链表********\n");

printf("********10:头插法*********\n");

printf("********11:尾插法*********\n");

printf("********12:合并表*********\n");

printf("********13:清  屏*********\n");

printf("***************************\n");

}

int main()

{

int input = 0;

int ret = 0;

int value = 0;

int position = 0;

int Length = 0;

int num = 0;

LinkList head;

InitList(head);

do

{

Menu();

printf("请输入你想使用的功能:");

scanf("%d", &input);

switch (input)

{

case 1:

printf("请输入你想插入的元素:");

scanf("%d", &value);

printf("请输入你想插入的位置:");

scanf("%d", &position);

ret = ListInsert_L(head, position, value);

if (!ret)

{

printf("插入失败,请重试\n");

}

else

{

printf("插入成功!\n");

}

break;

case 2:

if (ListEmpty(head))

{

printf("该链表为空表\n");

}

else

{

printf("该链表不是空表\n");

}

break;

case 3:

Length = ListLength_L(head);

printf("该链表的长度为:%d\n", Length);

break;

case 4:

printf("请输入你想查找的位置:");

scanf("%d", &position);

if (GetElem_L(head, position, value))

{

printf("第%d位的元素为%d\n", position, value);

}

else

{

printf("您输入的位置不合法\n");

}

break;

case 5:

printf("请输入你想查找的值:");

scanf("%d", &value);

position = LocateElem_L_Value(head, value);

if (position)

{

printf("你想查找的元素%d第一次出现在第%d位\n", value, position);

}

else

{

printf("未找到\n");

}

break;

case 6:

Output(head);

break;

case 7:

printf("请输入你想删除的位置:");

scanf("%d", &position);

if (ListDelete_L(head, position, value))

{

printf("你成功删除了第%d个元素%d\n", position, value);

}

else

{

printf("删除失败,请重试\n");

}

break;

case 8:

if (ClearList(head))

{

printf("清空链表成功\n");

}

else

{

printf("清空失败,请重试\n");

}

break;

case 9:

printf("您真的要销毁链表吗?\n1:确认\t0:取消\n");

scanf("%d", &ret);

if (ret == 1)

{

if (DestoryList_L(head))

{

printf("销毁成功\n");

}

else

{

printf("销毁失败\n");

}

}

else

{

printf("取消销毁\n");

}

break;

case 10:

//此时使用头插法会清空之前插入的链表

printf("请输入你想插入的元素个数:");

scanf("%d", &num);

CreatList_H(head, num);

printf("插入成功\n");

break;

case 11:

//此时使用尾插法会清空之前插入的链表

printf("请输入你想插入的元素个数:");

scanf("%d", &num);

CreatList_R(head, num);

printf("插入成功\n");

break;

case 12:

printf("使用尾插法建立两个递增链表:\n");

printf("请输入你想新建的链表1元素个数:");

scanf("%d", &num);

LinkList head1;

InitList(head1);

CreatList_R(head1, num);

printf("请输入你想新建的链表2的元素个数:");

scanf("%d", &num);

LinkList head2;

InitList(head2);

CreatList_R(head2, num);

LinkList head3;

InitList(head3);

MergeList_L(head1, head2, head3);

printf("合并后的链表:");

Output(head3);

break;

case 13:

system("cls");

break;

case 0:

exit(0);

break;

default:

printf("输入有误,请重新输入\n");

break;

}

} while (1);

return 0;

}

Status InitList(LinkList& L)//链表初始化

{

L = (LinkList)malloc(sizeof(LNode));

if (!L)

{

exit(OVERFLOW);

}

L->next = NULL;

return OK;

}

Status ListInsert_L(LinkList& L, int i, ElemType e)//在第i个位置之前插入元素e

{

LinkList p = L;

int j = 0;

while (p && j < i - 1)//注意是i-1,因为要找被插入元素的前一个元素

{

p = p->next;

j++;

}

if (!p || j > i - 1)

{

return ERROR;

}

LinkList s = (LinkList)malloc(sizeof(LNode));

if (!s)

{

exit(OVERFLOW);

}

s->data = e;

s->next = p->next;

p->next = s;

return OK;

}

int ListEmpty(LinkList L)//判断链表是否为空

//空表:头指针和头结点仍然存在,但头结点指向NULL

{

if (L->next)

{

return 0;

}

else

{

return 1;

}

}

int ListLength_L(LinkList L)//求线性表表长

{

LNode* p;

p = L->next;

int i = 0;

while (p)

{

i++;

p = p->next;

}

return i;

}

Status GetElem_L(LinkList L, int i, ElemType& e)//查找第i个元素是什么

{

LinkList p = L->next;

int j = 1;

while (p && j < i)

{

p = p->next;

j++;

}

if (!p || j > i)

{

return ERROR;//表示第i个元素不存在

}

e = p->data;

return OK;

}

int LocateElem_L_Value(LinkList L, ElemType e)//按值查找值为e的元素并返回其位置

//查找失败返回NULL

{

LNode* p = L->next;

int j = 1;

while (p && p->data != e)

{

p = p->next;

j++;

}

if (p)

{

return j;

}

else

{

return 0;

}

}

void Output(LinkList L)//打印线性链表中所有元素

{

if (L->next == NULL)

{

printf("该链表为空表\n");

return;

}

LNode* p = L->next;

while (p)

{

printf("%d ", p->data);

p = p->next;

}

printf("\n");

}

Status ListDelete_L(LinkList& L, int i, ElemType& e)//删除第i个元素并由e返回其值

{

LinkList p = L;

int j = 0;

while (p->next && j < i - 1)//注意删除是p->next,插入是p

{

p = p->next;

j++;

}

if (!(p->next) || j > i - 1)

{

return ERROR;

}

LinkList q = p->next;//注意删除要先定义一个指针记录被删除的元素,再把指针free掉

p->next = q->next;

e = q->data;//用e来保存被删除的元素

free(q);

return OK;

}

Status ClearList(LinkList& L)//清空单链表

//清空保留头指针、头结点

{

LNode* p, * q;

p = L->next;

while (p)

{

q = p->next;

free(p);

p = q;

}

L->next = NULL;

return OK;

}

Status DestoryList_L(LinkList& L)//销毁单链表

//销毁包括头指针、头结点

{

LNode* p;

while (L)

{

p = L;

L = L->next;

free(p);

}

return OK;

}

void CreatList_H(LinkList& L, int n)//用头插法快速建立链表

{

L = (LinkList)malloc(sizeof(LNode));

if (!L)

{

exit(OVERFLOW);

}

L->next = NULL;

for (int i = n; i > 0; i--)//倒序插入

{

LNode* p = (LinkList)malloc(sizeof(LNode));

if (!p)

{

exit(OVERFLOW);

}

scanf("%d", &p->data);

p->next = L->next;

L->next = p;

}

}

void CreatList_R(LinkList& L, int n)//尾插法快速建立链表

{

L = (LinkList)malloc(sizeof(LNode));

if (!L)

{

exit(OVERFLOW);

}

L->next = NULL;

LNode* r = L;//尾指针

for (int i = 0; i < n; i++)

{

LNode* p = (LinkList)malloc(sizeof(LNode));

if (!p)

{

exit(OVERFLOW);

}

p->next = NULL;

scanf("%d", &p->data);

r->next = p;//插入到表尾

r = p;//尾指针指向新的尾结点

}

}

void MergeList_L(LinkList& La, LinkList& Lb, LinkList& Lc)//已知单链线性表La和Lb的元素按值递增排列,归并得递增排列的Lc

{

LNode* pa = La->next;

LNode* pb = Lb->next;

LNode* pc = La;

Lc = pc;

while (pa && pb)

{

if (pa->data <= pb->data)

{

pc->next = pa;

pc = pa;//指针后移

pa = pa->next;

}

else

{

pc->next = pb;

pc = pb;

pb = pb->next;

}

}

pc->next = pa ? pa : pb;

free(Lb);

}

《数据结构(C语言版)》动态单链表的实现的评论 (共 条)

分享到微博请遵守国家法律