【链表】双向链表知识点-内含代码基本操作及其说明

目录

一、概念

二、双向链表基本操作

①初始化

②头插法

③尾插

④输出函数

⑤插入

⑥查找

⑦获取前驱

⑧获取后继

⑨删除数据

⑩删除

⑩①判空

 ⑩②获得长度

⑩③获取链表pos位置的值

⑩④清空\销毁链表

三、完整代码

1. dlist.h头文件

2. dlist.cpp


一、概念

        循环链表虽然能够实现从任一结点出发沿着链能找到其前驱结点,但时间消耗0(n),双向链表可以实现快速查找到前驱。例如用链表实现逆置时需要很多前移和后移的操作,很麻烦,而引入双向链表,增加对当前结点前驱的存储就很便捷。

结点定义代码如下:

typedef struct DNode
{
        int data;//数据
        struct DNode* next;//后继指针
        struct DNode* prior;//前驱指针
}DNode,*DList;

二、双向链表基本操作

只有涉及到前驱的头插、尾插、删除、函数需要修改,别的函数与单链表写法一致

①初始化

//初始化
//前驱和后继置空
void   InitList(DList plist)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return;
	}
	plist->next = NULL;
	plist->prio = NULL;
}

②头插法

步骤:

  1. 创建新结点
  2. 赋值
  3. 插入到头部

bool  Insert_head(DList plist, int val)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return false;
	}
	//创建新结点
	DNode* p = (DNode*)malloc(sizeof(DNode));
	assert(p != NULL);
	p->data = val;

	//插入新结点
	p->next = plist->next;//1
	plist->next = p;//2
	p->prio = plist;//把前驱结点也连接上,3
	if (p->next != NULL)//判断很重要
	{
		p->next->prio = p;//4
	}
	
	return true;
}

代码解释:

  • 1.把p结点插入到plist后面
  • 断开原结点,将p连接到plist后面(把plist->next的地址500存入到p->next内)
  • p->next=plist->next
  • 2.连接p与plist(将p的地址800存入到plist->next内)
  • plist->next=p
  • 3.连接p前驱结点plist    p->prior=plist;
  • 4.连接p->next的前驱p
  • p->next->prior=p;
  • !!此处直接这样写会报错,因为p->next可能为NULL
  • 比如这样的结点。因此需要对其判空操作。

③尾插

步骤:

  1. 创建新结点
  2. 赋值
  3. 找尾巴
  4. 插入到尾部处//只有这一步代码要修改,涉及到前驱结点
//尾插(考试重点)
bool  Insert_tail(DList plist, int val)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return  false;
	}
	//创建新结点
	DNode* p = (DNode*)malloc(sizeof(DNode));
	assert(p != NULL);
	p->data = val;

	//找尾巴
	DNode* q;
	for (q = plist; q->next != NULL; q = q->next)
	{
		;
	}
	//插入数据,将p插入到q的后面
	p->next = q->next;//也可以写:p->next=NULL;
	p->prio = q;
	q->next = p;

	return true;
}

输出函数

遍历链表,输出数值

//输出plist的所有数据
void Show(DList plist)
{
	for (DNode* p = plist->next; p != NULL; p = p->next)
	{
		printf("%d", p->data);
	}
	printf("\n");
}

⑤插入

插入数据,在plist链表的pos位置插入val

//插入数据,在plist链表的pos位置插入val;
bool  Insert(DList plist, int pos, int val)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return false;
	}
	if (pos<0 || pos>GetLength(plist))
	{
		return false;
	}
	//申请结点
	DNode* p = (DNode*)malloc(sizeof(DNode));
	assert(p != NULL);
	p->data = val;

	//找位置
	DNode* q;
	int i = 0;
	for (q = plist; i < pos; i++, q = q->next)
	{
		;
	}

	//插入数据
	//将p插入到q的后面;
	p->next = q->next;
	q->next = p;
	p->prio = q;
	if (p->next != NULL)
	{
		p->next->prio = p;
	}
	return true;
}

⑥查找

遍历链表,在plist查找第一个key值,找到返回结点地址,没有找到返回NULL

//在plist查找第一个key值,找到返回结点地址,没有找到返回NULL;
DNode* Search(DList plist, int key)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return NULL;
	}
	for (DNode* p = plist->next; p != NULL; p = p->next)
	{
		if(p->data==key)
		{
			return p;
		}
	}
	return NULL;
}

⑦获取前驱

//返回key的前驱地址,如果不存在返回NULL;
DNode* GetPrio(DList plist, int key)
{
	DNode* p = Search(plist, key);
	return p == NULL ? NULL : p->prio;
}

⑧获取后继

//返回key的后继地址,如果不存在返回NULL;
DNode* GetNext(DList plist, int key)
{
	DNode* p = Search(plist, key);
	return p == NULL ? NULL : p->next;
}

⑨删除数据

调用上面search函数,返回查找到数据的结点,删除该结点

删除操作为:将该结点的前驱的后继指向该节点的后继,该节点后继的前驱指向该节点的前驱。

//删除第一个val的值(考试重点)
bool  DelVal(DList plist, int val)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return false;
	}
	DNode* p = Search(plist, val);
	if (p == NULL)
	{
		return false;
	}
	p->prio->next = p->next;
	if (p->next != NULL)
	{
		p->next->prio = p->prio;
	}
	free(p);
	return true;
}

⑩删除

删除pos位置的值

//删除pos位置的值
bool  DelPos(DList plist, int pos)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return false;
	}

	if (pos < 0 || pos >= GetLength(plist))
	{
		return false;
	}

	//找位置
	DNode* p;
	int i;
	for (p = plist, i = 0; i < pos; i++, p = p->next)
	{
		;
	}

	DNode* q = p->next;//q是要删除的点
	//删除
	p->next = q->next;
	if (q->next != NULL)
	{
		q->next->prio = q->prio;
	}
	
	free(q);
	return true;
}

⑩①判空

//判断plist是否为空链表(没有数据节点)
bool IsEmpty(DList plist)
{
	return plist->next == NULL;
}

 ⑩②获得长度

//获取数据结点的个数
int  GetLength(DList plist)
{
	int count = 0;
	for (DNode* p = plist->next; p != NULL; p = p->next)
	{
		count++;
	}
	return count;
}

⑩③获取链表pos位置的值

遍历数组,条件为i<pos;不满足时为i==pos,直接将此时结点的值给rtval。

//获取plist链表的pos位置的值
bool GetElem(DList plist, int pos, int* rtval)//rtval:输出参数
{
	if (pos < 0 || pos >= GetLength(plist))
		return false;
	DNode* p = plist->next;
	for (int i = 0; i < pos; i++, p = p->next)
		;
	*rtval = p->data;
	return true;
}

⑩④清空\销毁链表

//销毁整个内存
void  Destroy(DList plist)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return;
	}
	//总是删除第一个点;
	DNode* p;
	while (plist->next != NULL)
	{
		p = plist->next;
		plist->next = p->next;
		free(p);
	}
}

三、完整代码

1. dlist.h头文件

//双向链表
typedef  struct  DNode
{
	int data;//数据域
	struct DNode* next;//后继指针
	struct DNode* prio;//前驱指针
}DNode,*DList;

//初始化
void   InitList(DList plist);

//头插
bool  Insert_head(DList plist, int val);

//尾插
bool   Insert_tail(DList plist, int val);

//插入数据,在plist链表的pos位置插入val;
bool  Insert(DList plist, int pos, int val);

//判空
bool   IsEmpty(DList plist);

//获取数据结点的个数
int  GetLength(DList plist);

//在plist查找第一个key值,找到返回结点地址,没有找到返回NULL;
DNode* Search(DList plist, int key);

//删除pos位置的值
bool  DelPos(DList plist, int pos);


//删除第一个val的值
bool  DelVal(DList plist, int val);

//返回key的前驱地址,如果不存在返回NULL;
DNode* GetPrio(DList plist, int key);


//返回key的后继地址,如果不存在返回NULL;
DNode* GetNext(DList plist, int key);

//输出
void  Show(DList plist);


//清空数据
void  Clear(DList plist);

//销毁整个内存
void  Destroy(DList plist);


2. dlist.cpp

#include "dlist.h"
#include <assert.h>
#include <stdlib.h>
#include  <stdio.h>
//初始化
void   InitList(DList plist)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return;
	}
	plist->next = NULL;
	plist->prio = NULL;
}

//头插(考试重点)
bool  Insert_head(DList plist, int val)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return false;
	}
	//创建新结点
	DNode* p = (DNode*)malloc(sizeof(DNode));
	assert(p != NULL);
	p->data = val;

	//插入新结点
	p->next = plist->next;//绑线
	plist->next = p;
	p->prio = plist;
	if (p->next != NULL)//判断很重要
	{
		p->next->prio = p;
	}
	
	return true;
}

//尾插(考试重点)
bool   Insert_tail(DList plist, int val)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return  false;
	}
	//创建新结点
	DNode* p = (DNode*)malloc(sizeof(DNode));
	assert(p != NULL);
	p->data = val;

	//找尾巴
	DNode* q;
	for (q = plist; q->next != NULL; q = q->next)
	{
		;
	}
	//插入数据,将p插入到q的后面
	p->next = q->next;//p->next=NULL;
	p->prio = q;
	q->next = p;

	return true;

}

//插入数据,在plist链表的pos位置插入val;
bool  Insert(DList plist, int pos, int val)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return false;
	}
	if (pos<0 || pos>GetLength(plist))
	{
		return false;
	}
	//申请结点
	DNode* p = (DNode*)malloc(sizeof(DNode));
	assert(p != NULL);
	p->data = val;

	//找位置
	DNode* q;
	int i = 0;
	for (q = plist; i < pos; i++, q = q->next)
	{
		;
	}

	//插入数据
	//将p插入到q的后面;
	p->next = q->next;
	q->next = p;
	p->prio = q;
	if (p->next != NULL)
	{
		p->next->prio = p;
	}
	return true;
}

//判空
bool   IsEmpty(DList plist)
{
	return plist->next == NULL;
}

//获取数据结点的个数
int  GetLength(DList plist)
{
	int count = 0;
	for (DNode* p = plist->next; p != NULL; p = p->next)
	{
		count++;
	}
	return count;
}

//在plist查找第一个key值,找到返回结点地址,没有找到返回NULL;
DNode* Search(DList plist, int key)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return NULL;
	}
	for (DNode* p = plist->next; p != NULL; p = p->next)
	{
		if(p->data==key)
		{
			return p;
		}
	}
	return NULL;
}

//删除pos位置的值
bool  DelPos(DList plist, int pos)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return false;
	}

	if (pos < 0 || pos >= GetLength(plist))
	{
		return false;
	}

	//找位置
	DNode* p;
	int i;
	for (p = plist, i = 0; i < pos; i++, p = p->next)
	{
		;
	}

	DNode* q = p->next;//q是要删除的点
	//删除
	p->next = q->next;
	if (q->next != NULL)
	{
		q->next->prio = q->prio;
	}
	
	free(q);
	return true;
}


//删除第一个val的值(考试重点)
bool  DelVal(DList plist, int val)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return false;
	}
	DNode* p = Search(plist, val);
	if (p == NULL)
	{
		return false;
	}
	p->prio->next = p->next;
	if (p->next != NULL)
	{
		p->next->prio = p->prio;
	}
	free(p);
	return true;
}

//返回key的前驱地址,如果不存在返回NULL;
DNode* GetPrio(DList plist, int key)
{
	DNode* p = Search(plist, key);
	return p == NULL ? NULL : p->prio;
}


//返回key的后继地址,如果不存在返回NULL;
DNode* GetNext(DList plist, int key)
{
	DNode* p = Search(plist, key);
	return p == NULL ? NULL : p->next;
}

//输出
void  Show(DList plist)
{
	for (DNode* p = plist->next; p != NULL; p = p->next)
	{
		printf("%d  ", p->data);
	}
	printf("\n");
}


//清空数据
void  Clear(DList plist)
{
	Destroy(plist);
}

//销毁整个内存
void  Destroy(DList plist)
{
	assert(plist != NULL);
	if (plist == NULL)
	{
		return;
	}
	//总是删除第一个点;
	DNode* p;
	while (plist->next != NULL)
	{
		p = plist->next;
		plist->next = p->next;
		free(p);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值