C语言实现双链表

C语言实现双链表

说明

图片自己画的,有点丑,不要介意。
本文来自专栏:数据结构
后续还会继续coding。如果有需要可以关注点赞一波。

实现的功能

  • 插入结点
  • 删除结点
  • 从头到尾遍历输出所有元素
  • 获取某个结点的前驱和其后继结点

获取前驱和后继主要是为了测试双链表是否编写正确,因为双链表可以访问前驱,这是与单链表不同的地方。

结构体定义

typedef struct BiLinkNode
{
	ElemType data;
	struct BiLinkNode *rlink,*llink;//分别代表左指针和右指针,分别指向前驱和后继,一般也写作prior和next
}BiLink;

初始化

//初始化双链表(带头结点) 
bool InitBiLinkList(BiLink *B)
{
	//先申请一个头结点
	BiLink *head = (BiLink *)malloc(sizeof(BiLink));
	//左右指针初始为空,且表长为0 
	head->llink = B;
	B->rlink = head;
	head->rlink = NULL;//头结点之后一开始还没元素
	return true;
} 

插入结点

​ 如下图所示:

p1

​ 绿色实线是插入前的结构,虚线是我们要进行的操作。S代表新插入的结点。

​ 这里我进行的操作顺序是①②③④,当然也可以修改顺序,比如③和④的顺序可以调换。这些操作对应的代码实现是:

​ ①s->rlink = p->rlink;

​ ②p->rlink->llink = s;

​ ③p->rlink = s;

​ ④s->llink = p;

​ 这里我使用了头插法实现,欢迎大家使用尾插法尝试。

//插入
bool InsertBiLinkList(BiLink *B,ElemType e)
{
	//头插法
	BiLink *p = B;//
	
	//申请一个新的结点
	BiLink *s = (BiLink *)malloc(sizeof(BiLink));
	
	s->data = e;//赋值 
	
	//修改指针  将结点s插入到结点p之后 
	s->rlink = p->rlink;//s指针指向
	p->rlink->llink = s;
	
	p->rlink = s;
	s->llink = p;
	
	length++;//元素个数加一
	return true;
} 

删除结点

如图:

image-20211001221250481

删除操作比插入操作要简单得多,我们只需要修改q->llink的右指针和q->rlink的左指针,将其分别指向q->rlink和q-<llink即可。

bool DeleteBinList(BiLink *B,ElemType *e)//根据值删除某个结点
{
	BiLink *q;
	q = B->rlink;

	while(q->rlink!=NULL)//先遍历 
	{
		if(q->data == e)//首先找到这个结点
		{
			q->llink->rlink = q->rlink;//修改q结点前面的后继指针
			q->rlink->llink = q->llink;//修改q结点后面的前驱指针 
		} 
		q = q->rlink;
	}
	length--;
	return true;
} 

输出所有元素

只需从头到尾遍历或者从尾到头遍历即可。这里我实现从头到尾遍历。

void PrintAll(BiLink *B)
{
	BiLink *q;
	q = B->rlink;

	//打印出所有元素 
	while(q->rlink!=NULL)
	{
		printf("%d ",q->data);
		q = q->rlink;//只要没到末尾,指针++
	}
}

全部代码

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h> //根据C99标准,C语言使用bool类型需要添加这个头文件

typedef int ElemType;

typedef struct BiLinkNode
{
	ElemType data;
	struct BiLinkNode *rlink,*llink;
}BiLink;

//------------ 函数声明 ----------//
void MainMenu();
bool GetLen(BiLink *B);//获取表长度,并且直接打印在屏幕上 
bool InitBiLinkList(BiLink *B);//初始化 
bool InsertBiLinkList(BiLink *B,ElemType e);//插入
void PrintAll(BiLink *B);//输出所有元素
bool GetPriorNode(BiLink *B,ElemType e,ElemType *ldata);//查找元素为e的前驱结点的值 
bool GetNextNode(BiLink *B,ElemType e,ElemType *rdata);//查找元素为e的后继结点的值
bool DeleteBinList(BiLink *B,ElemType *e);//根据值删除某个结点 
//------------ 函数声明 ----------//

int length; //表中实际长度 

int main()
{
	BiLink B;
	
	int ch; 
	ElemType element,num,ldata,rdata;
	
	if(InitBiLinkList(&B))
		printf("初始化成功!\n");
	else
		printf("初始化失败!\n");
	
	while(1)
	{
		MainMenu(); 
		printf("请输入您要执行的操作:");
		scanf("%d",&ch);
		
		switch(ch)
		{
			case 0:		printf("感谢使用,已退出!");	exit(0);	break;
			case 1:		printf("请输入您要插入的元素:\n");
						scanf("%d",&element); 
						if(InsertBiLinkList(&B,element))
							printf("插入成功!\n");
						else
							printf("插入失败!\n");
						break;
			case 2:		PrintAll(&B);
						break;		
			case 3:		if(GetLen(&B))
							printf("获取成功!");
						else
							printf("获取失败!");
						break; 
						
			case 4:		
						printf("请输入你要获取的当前结点的值:\n");
						scanf("%d",&num);
						if(GetPriorNode(&B,num,&ldata))
							printf("获取成功,%d的前一结点的值为:%d\n",num,ldata);
						else
							printf("获取失败!");
						break;
			case 5: 
						printf("请输入你要获取的当前结点的值:\n");
						scanf("%d",&num);
						if(GetNextNode(&B,num,&rdata))
							printf("获取成功,%d的后一结点的值为:%d\n",num,rdata);
						else
							printf("获取失败!");
						break;
			case 6: 
						printf("请输入你要删除的结点的值:\n");
						scanf("%d",&num);
						if(DeleteBinList(&B,num))
							printf("删除成功!\n");
						else
							printf("删除失败!");
						break;
			default:	printf("您输入的操作指令有误!请重新输入!");
		}
	}
	
	return 0;
}

//主菜单,显示 
void MainMenu()
{
	printf("\n\n\n");
	printf("\t      ************* 双链表的实现 ************\n\n"); 
	printf("\t      -------	0.退出 \n\n");
	printf("\t      -------	1.插入元素\n\n");
	printf("\t      -------	2.输出所有元素\n\n");
	printf("\t      -------	3.获取表长度\n\n");
	printf("\t      -------	4.获取某个结点的前驱结点的值\n\n");
	printf("\t      -------	5.获取某个结点的后继结点的值\n\n");
	printf("\t      -------	6.删除一个结点\n\n");
	printf("\t      *************************************\n");
}


//初始化双链表(带头结点) 
bool InitBiLinkList(BiLink *B)
{
	//先申请一个头结点
	BiLink *head = (BiLink *)malloc(sizeof(BiLink));
	//左右指针初始为空,且表长为0 
	head->llink = B;
	B->rlink = head;
	head->rlink = NULL;//头结点之后一开始还没元素
	return true;
} 

//插入
bool InsertBiLinkList(BiLink *B,ElemType e)
{
	//头插法
	BiLink *p = B;//
	
	//申请一个新的结点
	BiLink *s = (BiLink *)malloc(sizeof(BiLink));
	
	s->data = e;//赋值 
	
	//修改指针  将结点s插入到结点p之后 
	s->rlink = p->rlink;//s指针指向
	p->rlink->llink = s;
	
	p->rlink = s;
	s->llink = p;
	
	length++;//元素个数加一
	return true;
} 


bool GetLen(BiLink *B)
{
	printf("表长为:%d\n",length);
	return true;
}

void PrintAll(BiLink *B)
{
	BiLink *q;
	q = B->rlink;

	//打印出所有元素 
	while(q->rlink!=NULL)
	{
		printf("%d ",q->data);
		q = q->rlink;
	}
}

bool GetPriorNode(BiLink *B,ElemType e,ElemType *ldata)//查找元素为e的前驱结点的值
{
	BiLink *q;
	q = B->rlink;
 
	while(q->rlink!=NULL)
	{
		if(q->data == e)//首先找到这个结点 
			*ldata = q->llink->data;
		q = q->rlink;
	}
	return true;
}

bool GetNextNode(BiLink *B,ElemType e,ElemType *rdata)//查找元素为e的后继结点的值
{
	BiLink *q;
	q = B->rlink;
 
	while(q->rlink!=NULL)
	{
		if(q->data == e)//首先找到这个结点
			*rdata = q->rlink->data;
		q = q->rlink;
	}
	return true;
}

bool DeleteBinList(BiLink *B,ElemType *e)//根据值删除某个结点
{
	BiLink *q;
	q = B->rlink;

	while(q->rlink!=NULL)
	{
		if(q->data == e)//首先找到这个结点
		{
			q->llink->rlink = q->rlink;//修改q结点前面的后继指针
			q->rlink->llink = q->llink;//修改q结点后面的前驱指针 
		} 
		q = q->rlink;
	}
	length--; 
	return true;
} 

测试

image-20211001221741932

image-20211001221800949

image-20211001221836516

image-20211001221906891

image-20211001221947532

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值