数据结构三:双链表(C/C++实现)

目录

双链表(C):

双链表(C++):

测试结果:

总结:


双链表比单链表多了个指向前一个结点的指针,更方便进行插入和删除操作。

代码使用带头结点的链表,这样可以方便实现代码。

并且在初始化链表的时候使用尾插法建立链表。

双链表(C):

#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;
typedef struct DNode {	//双链表结点
	ElemType data;
	struct DNode* prior, * next;
}DNode,*DLinkList;

//默认采用带头结点、尾插法建立链表(方便写代码)
int DListInit(DLinkList* L)//此处的L为二级指针
{
	int x;
	*L = (DLinkList)malloc(sizeof(DNode));	//头结点
	if (*L == NULL)	return 0;
	(*L)->prior = NULL;
	(*L)->next = NULL;
	DNode* r = *L;//尾指针
	scanf_s("%d", &x);
	while (x != 9999) {
		DNode* s = (DNode*)malloc(sizeof(DNode));
		if (s == NULL)	return 0;
		s->data = x;
		r->next = s;
		s->prior = r;
		r = s;		//尾插s,同时移动尾指针
		scanf_s("%d", &x);
	}
	r->next = NULL;
	return 1;
}
//链表判空
int DListIsEmpty(DLinkList L)
{
	if (L->next == NULL)	
		return 1;
	else
		return 0;
}
//销毁链表
int DListDestory(DLinkList* L)
{
	DNode* p = (*L)->next;//p指向待删除结点
	while (p != NULL) {
		(*L)->next = p->next;
		p->next->prior = *L;	//连接头结点与p的后一个结点
		free(p);
		p = (*L)->next;
	}
	p = *L;
	free(p);
	p = NULL;
	*L = NULL;	//删除头结点
	return 1;
}
//查找第i个结点
DNode* DListSearchNode(DLinkList L, int i)
{
	if (i < 1)	return NULL;

	DNode* p = L->next;//p初始指向第一个结点
	int j = 1;//计数值
	while (p != NULL && j < i) {
		p = p->next;
		j++;
	}
	return p;
}
//按值查找结点
DNode* DListSearchElem(DLinkList L, ElemType e)
{
	DNode* p = L->next;//p初始指向第一个结点
	while (p != NULL && p->data != e) {
		p = p->next;
	}
	return p;
}
//求链表表长(头结点不算长度)
int DListLenth(DLinkList L)
{
	if (L == NULL)	return 0;

	DNode* p = L->next;//p初始指向第一个结点
	if (p == NULL)	return 0;
	int len = 1;
	while (p->next != NULL) {
		p = p->next;
		len++;
	}
	return len;
}
//在p结点之后插入s结点
int	InsertNextDNode(DNode* p, DNode* s)
{
	if (p == NULL || s == NULL)	return 0;

	s->next = p->next;
	if (p->next != NULL)
		p->next->prior = s;	//防止空指针出错
	s->prior = p;
	p->next = s;
	return 1;
}
//在p结点之前插入s结点
int InsertPriorDNode(DNode* p, DNode* s)
{
	if (p == NULL || s == NULL)	return 0;
	
	s->prior = p->prior;
	p->prior->next = s;
	s->next = p;
	p->prior = s;
	return 1;
}
//第i个位置后插结点e,新结点位于i处
int DListRearInsert(DLinkList* L, int i, ElemType e)
{
	DNode* p = DListSearchNode(*L, i - 1);//找到第i-1个结点
	if (p == NULL)	return 0;

	DNode* s = (DNode*)malloc(sizeof(DNode));
	if (s == NULL)	return 0;
	s->data = e;
	if (InsertNextDNode(p, s)) {//后插结点
		return 1;
	}
	else {
		return 0;
	}
}
//第i个位置前插入结点e,新节点位于i-1处
int DListFrontInsert(DLinkList* L, int i, ElemType e)
{
	DNode* p = DListSearchNode(*L, i - 1);//找到第i-1个结点
	if (p == NULL)	return 0;

	DNode* s = (DNode*)malloc(sizeof(DNode));
	if (s == NULL)	return 0;
	s->data = e;
	if (InsertPriorDNode(p, s)) {//前插结点
		return 1;
	}
	else {
		return 0;
	}
}
//删除第i个结点,并返回删除数据
int DListDeleteNode(DLinkList* L, int i, ElemType* e)
{
	DNode* p = DListSearchNode(*L, i - 1);//找到第i-1个结点
	if (p == NULL)	return 0;

	DNode* q = p->next;//q指向待删除结点
	if (q == NULL)	return 0;
	p->next = q->next;
	q->next->prior = p;
	*e = q->data;
	free(q);
	q = NULL;
	return 1;
}
//删除特定结点e
int DListDeleltNodeP(DLinkList* L, ElemType e)
{
	DNode* p = DListSearchElem(*L, e);//p指向待删除结点
	if (p == NULL)	return 0;

	if (p->next == NULL) {	//表示p为链表最后一个结点
		p->prior->next = NULL;
		free(p);
		p = NULL;
	}
	else {
		p->prior->next = p->next;
		p->next->prior = p->prior;
		free(p);
		p = NULL;
	}
	return 1;
}
//从头输出双链表
void DListPrint(DLinkList L)
{
	if (L == NULL || L->next == NULL)	return;

	DNode* p = L->next;
	int i = 1;
	while (p != NULL) {
		printf("data[%d]:%d     ", i, p->data);
		p = p->next;	//必须先输出再移动指针
		i++;
	}
	printf("\n");
}

int main()
{
	DLinkList L;
	/*************************链表初始化***************************/
	printf("请输入数据,构建链表:\n");
	DListInit(&L);
	if (DListIsEmpty(L)) {
		printf("链表为空!\n");
	}
	else {
		printf("链表非空!\n");
	}
	printf("链表中数据为:\n");
	DListPrint(L);
	printf("链表长度为:%d\n", DListLenth(L));
	/*************************************************************/


	/*************************插入、删除结点***********************/
	if (DListRearInsert(&L, 4, 12345)) {//在第4个位置后插入12345
		printf("在第4个位置后插入12345成功!\n");
		printf("链表中数据为:\n");
		DListPrint(L);
		printf("链表长度为:%d\n", DListLenth(L));
	}
	else {
		printf("在第4个位置后插入12345失败!\n");
	}
	printf("\n\n");
	if (DListFrontInsert(&L, 3, 999)) {//在第3个位置前插入999
		printf("在第3个位置前插入999成功!\n");
		printf("链表中数据为:\n");
		DListPrint(L);
		printf("链表长度为:%d\n", DListLenth(L));
	}
	else
	{
		printf("在第3个位置前插入999失败!\n");
	}
	printf("\n\n");
	int e;
	if (DListDeleteNode(&L, 5, &e)) {//删除第5个位置的结点
		printf("删除第5个结点成功!删除的数据为:%d\n", e);
		printf("链表中数据为:\n");
		DListPrint(L);
		printf("链表长度为:%d\n", DListLenth(L));
	}
	else {
		printf("删除第5个结点失败!");
	}
	printf("\n\n");
	/*************************************************************/

	system("pause");
	return 0;
}

双链表(C++):

#include <iostream>

typedef int ElemType;
typedef struct DNode {	//双链表结点
	ElemType data;
	struct DNode* prior, * next;
}DNode, * DLinkList;

//默认采用带头结点、尾插法建立链表(方便写代码)
//C++可以使用引用,不需要操作二级指针;还可以使用bool来进行判断
bool DListInit(DLinkList& L)
{
	int x;
	L = (DLinkList)malloc(sizeof(DNode));	//头结点
	if (L == NULL)	return false;
	L->prior = NULL;
	L->next = NULL;
	DNode* r = L;//尾指针
	scanf_s("%d", &x);
	while (x != 9999) {
		DNode* s = (DNode*)malloc(sizeof(DNode));
		if (s == NULL)	return false;
		s->data = x;
		r->next = s;
		s->prior = r;
		r = s;		//尾插s,同时移动尾指针
		scanf_s("%d", &x);
	}
	r->next = NULL;
	return true;
}
//链表判空
bool DListIsEmpty(DLinkList L)
{
	if (L->next == NULL)
		return true;
	else
		return false;
}
//销毁链表
bool DListDestory(DLinkList& L)
{
	DNode* p = L->next;//p指向待删除结点
	while (p != NULL) {
		L->next = p->next;
		p->next->prior = L;	//连接头结点与p的后一个结点
		free(p);
		p = L->next;
	}
	p = L;
	free(p);
	p = NULL;
	L = NULL;	//删除头结点
	return true;
}
//查找第i个结点
DNode* DListSearchNode(DLinkList L, int i)
{
	if (i < 1)	return NULL;

	DNode* p = L->next;//p初始指向第一个结点
	int j = 1;//计数值
	while (p != NULL && j < i) {
		p = p->next;
		j++;
	}
	return p;
}
//按值查找结点
DNode* DListSearchElem(DLinkList L, ElemType e)
{
	DNode* p = L->next;//p初始指向第一个结点
	while (p != NULL && p->data != e) {
		p = p->next;
	}
	return p;
}
//求链表表长(头结点不算长度)
int DListLenth(DLinkList L)
{
	if (L == NULL)	return false;

	DNode* p = L->next;//p初始指向第一个结点
	if (p == NULL)	return false;
	int len = 1;
	while (p->next != NULL) {
		p = p->next;
		len++;
	}
	return len;
}
//在p结点之后插入s结点
bool InsertNextDNode(DNode* p, DNode* s)
{
	if (p == NULL || s == NULL)	return false;

	s->next = p->next;
	if (p->next != NULL)
		p->next->prior = s;	//防止空指针出错
	s->prior = p;
	p->next = s;
	return true;
}
//在p结点之前插入s结点
bool InsertPriorDNode(DNode* p, DNode* s)
{
	if (p == NULL || s == NULL)	return false;

	s->prior = p->prior;
	p->prior->next = s;
	s->next = p;
	p->prior = s;
	return true;
}
//第i个位置后插结点e,新结点位于i处
bool DListRearInsert(DLinkList& L, int i, ElemType e)
{
	DNode* p = DListSearchNode(L, i - 1);//找到第i-1个结点
	if (p == NULL)	return false;

	DNode* s = (DNode*)malloc(sizeof(DNode));
	if (s == NULL)	return false;
	s->data = e;
	if (InsertNextDNode(p, s)) {//后插结点
		return true;
	}
	else {
		return false;
	}
}
//第i个位置前插入结点e,新节点位于i-1处
bool DListFrontInsert(DLinkList& L, int i, ElemType e)
{
	DNode* p = DListSearchNode(L, i - 1);//找到第i-1个结点
	if (p == NULL)	return false;

	DNode* s = (DNode*)malloc(sizeof(DNode));
	if (s == NULL)	return false;
	s->data = e;
	if (InsertPriorDNode(p, s)) {//前插结点
		return true;
	}
	else {
		return false;
	}
}
//删除第i个结点,并返回删除数据
bool DListDeleteNode(DLinkList& L, int i, ElemType& e)
{
	DNode* p = DListSearchNode(L, i - 1);//找到第i-1个结点
	if (p == NULL)	return false;

	DNode* q = p->next;//q指向待删除结点
	if (q == NULL)	return false;
	p->next = q->next;
	q->next->prior = p;
	e = q->data;
	free(q);
	q = NULL;
	return true;
}
//删除特定结点e
bool DListDeleltNodeP(DLinkList& L, ElemType e)
{
	DNode* p = DListSearchElem(L, e);//p指向待删除结点
	if (p == NULL)	return false;

	if (p->next == NULL) {	//表示p为链表最后一个结点
		p->prior->next = NULL;
		free(p);
		p = NULL;
	}
	else {
		p->prior->next = p->next;
		p->next->prior = p->prior;
		free(p);
		p = NULL;
	}
	return true;
}
//从头输出双链表
void DListPrint(DLinkList L)
{
	if (L == NULL || L->next == NULL)	return;

	DNode* p = L->next;
	int i = 1;
	while (p != NULL) {
		printf("data[%d]:%d     ", i, p->data);
		p = p->next;	//必须先输出再移动指针
		i++;
	}
	printf("\n");
}

int main()
{
	DLinkList L;
	/*************************链表初始化***************************/
	std::cout << "请输入数据,构建链表:\n";
	DListInit(L);
	if (DListIsEmpty(L)) {
		std::cout << "链表为空!\n";
	}
	else {
		std::cout << "链表非空!\n";
	}
	std::cout << "链表中数据为:\n";
	DListPrint(L);
	std::cout << "链表长度为:" << DListLenth(L) << std::endl;
	/*************************************************************/


	/*************************插入、删除结点***********************/
	if (DListRearInsert(L, 4, 12345)) {//在第4个位置后插入12345
		std::cout << "在第4个位置后插入12345成功!\n";
		std::cout << "链表中数据为:\n";
		DListPrint(L);
		std::cout << "链表长度为:" << DListLenth(L) << std::endl;
	}
	else {
		std::cout << "在第4个位置后插入12345失败!\n";
	}
	std::cout << "\n" << std::endl;
	if (DListFrontInsert(L, 3, 999)) {//在第3个位置前插入999
		std::cout << "在第3个位置前插入999成功!\n";
		std::cout << "链表中数据为:\n";
		DListPrint(L);
		std::cout << "链表长度为:" << DListLenth(L) << std::endl;
	}
	else
	{
		std::cout << "在第3个位置前插入999失败!\n";
	}
	std::cout << "\n" << std::endl;
	int e;
	if (DListDeleteNode(L, 5, e)) {//删除第5个位置的结点
		std::cout << "删除第5个结点成功!删除的数据为:" << e << std::endl;
		std::cout << "链表中数据为:\n";
		DListPrint(L);
		std::cout << "链表长度为:" << DListLenth(L) << std::endl;
	}
	else {
		std::cout << "删除第5个结点失败!\n";
	}
	std::cout << "\n" << std::endl;
	/*************************************************************/

	system("pause");
	return 0;
}

测试结果:

总结:

双链表插入以及删除的时候要小心操作指针,防止发生空指针错误、指向不正确等问题。

以上

以上均为个人学习心得,如有错误,请不吝赐教~

THE END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值