数据结构— —双向链表

双向链表的算法实现

单链表中每个结点除了存储自身数据之后,还存储了下一个结点的地址,因此可以轻松访问下一个结点,以及后面的后继结点,但是如果想访问前面的结点就不行了,再也回不去了。例如删除结点 p 时,要先找到它的前一个结点 q,然后才能删掉 p 结点,单向链表只能往后走,不能向前走。如果需要向前走,怎么办呢?

可以在单链表的基础上给每个元素附加两个指针域,一个存储前一个元素的地址,一个存储下一个元素的地址。这种链表称为双向链表.

 

其结构体定义:

typedef struct _LinkNode {

int data; //结点的数据域 struct _LinkNode *next; //下一个节点的指针域

struct _LinkNode *prev; //上一个结点的指针域

}LinkNode, LinkList; //LinkList 为指向结构体 LNode 的指针类型

双向链表的初始

//前插法

bool DbListInsert_front(DbLinkList* &L, DbLinkNode *node){ if(!L || !node) return false;

//1.只有头节点

if(L->next==NULL){

typedef struct _DoubleLinkNode { int data; //结点的数据域

struct _DoubleLinkNode *next; //下一个节点的指针域 struct _DoubleLinkNode *prev; //上一个结点的指针域

}DbLinkNode, DbLinkList; //LinkList为指向结构体LNode的指针类型

bool DbInit_List(DbLinkList* &L)//构造一个空的双向链表L

{

L=new DbLinkNode; //生成新结点作为头结点,用头指针L指向头结点 if(!L)return false; //生成结点失败

L->next=NULL; //头结点的next指针域置空

L->prev=NULL; //头结点的指针域置空 L->data = -1; return true;

}

双向链表增加元素前插法

                  node->next=NULL;                           11

node->prev=L; //新节点prev 指针指向头节点 L->next=node; //头节点next 指针指向新节点

}else {

L->next->prev=node;  //第二个节点的prev 指向新节点 node->next = L->next; //新节点next指针指向第二个节点 node->prev=L;    //新节点prev 指针指向头节点

                  L->next=node;            //头节点next 指针指向新节点,完成插入

}

return true;

}

 尾插法

//尾插法

bool DbListInsert_back(DbLinkList* &L, DbLinkNode *node){ DbLinkNode *last = NULL; if(!L || !node) return false;

last = L;

while(last->next) last = last->next;

node->next = NULL;

last->next = node;

node->prev = last; return true; }

 

任意位置插入

//指定位置插入

bool DbLink_Insert(DbLinkList* &L, int i, int &e){ if(!L||!L->next) return false; if(i<1) return false;

int j =0;

DbLinkList *p, *s;

p = L;

while(p && j<i){//查找位置为i的结点,p指向该结点 p = p->next;

j++;

}

if(!p || j!=i){ cout<<"不存在节点:"<<i<<endl;

return false;

} cout<<"p: "<<p<<endl;

s=new DbLinkNode;//生成新节点

s->data = e;

s->next = p;

s->prev = p->prev;

p->prev->next = s;

p->prev = s;

return true;

}

双向链表的遍历

//双向链表的遍历输出

void DbLink_Print(DbLinkList* &L ){

DbLinkNode *p = NULL;

if(!L){

cout<<"链表为空."<<endl; return ;

}

p = L;

while(p->next){

cout<<p->next->data<<"\t";

p = p->next;

}

//逆向打印

cout<<endl<<"逆向打印"<<endl;

while(p){

cout<<p->data<<"\t";

p = p->prev;

}

cout<<endl;

}

双向链表获取元素

bool DbLink_GetElem(DbLinkList* &L, int i, int &e)//双向链表的取值

{

//在带头结点的双向链表L中查找第i个元素

//用e记录L中第i个数据元素的值

int index;

DbLinkList *p;

if(!L || !L->next) return false;

p = L->next;

index = 1;

while(p && index<i){//顺链表向后扫描,直到p指向第i个元素或p为空

p = p->next;

index++;

}

if(!p || index>i){ return false//i值不合法,i>n或i<=0

}

e=p->data; return true;

}

11

双向链表删除元素

//任意位置删除

bool DbLink_Delete(DbLinkList* &L, int i) //双向链表的删除

{

DbLinkList *p;

int index = 0;

if(!L || !L->next){

cout<<"双向链表为空!"<<endl;

return false;

}

if(i<1) return false; //不能删除头节点

p=L;

while(p && index<i){

p = p->next;

index++;

}

if(!p){ //当节点不存在时,返回失败 return false;

}

p->prev->next=p->next; //改变删除结点前驱结点的next 指针域 if(p->next){

p->next->prev = p->prev; //改变删除节点后继节点的prev 指针域

}

delete p;         //释放被删除结点的空间

return true;

}

11

双向链表销毁

void DbLink_Destroy(DbLinkList* &L) //双向链表的销毁

{

//定义临时节点p指向头节点

DbLinkList *p = L;

cout<<"销毁链表!"<<endl;

while(p){

L=L->next;//L指向下一个节点 cout<<"删除元素: "<<p->data<<endl; delete p; //删除当前节点

p = L;   //p 移向下一个节点

}

}

完整代码实现

#include <iostream>
#include <Windows.h>

using namespace std;

typedef struct _DbLinkList
{
	int data;//数据域
	struct _DbLinkList* prev;//前驱结点
	struct _DbLinkList* next;//后继结点

}DbLinkList, DbLinkNode;

bool DbLinkList_Init(DbLinkList*& L)
{
	//分配头结点
	L = new DbLinkNode;

	if (!L)
	{
		return false;
	}

	L->next = NULL;
	L->prev = NULL;
	L->data = -1;
	return true;
}

//头插
bool InsertDbLink_front(DbLinkList*& L, DbLinkList* node)
{
	if (!L || !node)
	{
		return false;
	}

	if (L->next == NULL)
	{
		node->next = NULL;
		node->prev = L;
		L->next = node;
	}
	else
	{
		L->next->prev = node;
		node->next = L->next;
		node->prev = L;
		L->next = node;

		//L->next->prev = node; //第二个节点的 prev 指向新节点
		//node->next = L->next; //新节点 next 指针指向第二个节点
		//node->prev = L; //新节点 prev 指针指向头节点
		//L->next = node;
	}

	return true;
}

//尾插
bool InsertDbLink_back(DbLinkList* &L, DbLinkNode* node)
{
	if (!L || !node)
	{
		return false;
	}

	DbLinkList* q;
	q = L;

	while (q->next)
	{
		q = q->next;
	}

	q->next = node;
	node->prev = node;
	return true;
}

//任意位置插入
bool DbLink_Insert(DbLinkList*& L,int i,int &e)
{
	DbLinkList* q, * s;
	int j = 1;
	

	q = L->next;
	
	if (!L || !L->next)
	{
		return false;
	}

	while (!q || j < i)
	{
		q = q->next;
		j++;
	}

	if (!q || i != j)
	{
		return false;
	}

	s = new DbLinkNode;
	s->data = e;

	q->prev->next = s;
	s->prev = q->prev;
	s->next = q;
	q->prev = s;

	return true;
}

//按指定位置查找元素
bool seekElem(DbLinkList*& L, int i, int& e)
{
	DbLinkList* p;
	int j = 1;

	p = L->next;

	if (!L || !L->next)
	{
		return false;
	}

	while (p && j < i)
	{
		p = p->next;
		j++;
	}

	if (!p || j > i)
	{
		return false;
	}

	e = p->data;

	return true;
}

bool DbLink_Delete(DbLinkList*& L, int i)
{
	DbLinkNode* pos;
	int j = 1;
	pos = L->next;

	if (!L || !L->next)
	{
		return false;
	}

	if (i < 1)
	{
		return false;
	}

	while (!pos ||j<i)
	{
		pos = pos->next;
		j++;
	}

	if (!pos)
	{
		return false;
	}


	pos->prev->next = pos->next;
	pos->next->prev = pos->prev;

	delete pos;

	return true;

}

//链表的销毁
void DestroyLink(DbLinkList* &L)
{
	DbLinkNode* q = L;

	if (!L)
	{
		cout << "链表为空" << endl;
	}

	while (q)
	{
		L = L->next;
		delete q;
		q = L;
	}

	cout << "链表销毁了" << endl;
}

void DbLink_Print(DbLinkList*& L)
{
	DbLinkNode* s = NULL;
	s = L;
	
	if (!L)
	{
		cout << "链表为空." << endl;
		return;
	}

	while (s->next)
	{
		s = s->next;
		cout << s->data << "\t";
	}
	cout << endl;

	while (s!=L)
	{
		cout << s->data << "\t";
		s = s->prev;
	}
	cout << endl;
}

int main(void)
{
	DbLinkList* L, * s, * a;

	//双向链表初始化
	if (DbLinkList_Init(L))
	{
		cout << "初始化循环链表成功" << endl;
	}
	else
	{
		cout << "初始化循环链表失败" << endl;
	}

	//前插
	int j;
	
	cout << "请输入你要插入的个数:";
	cin >> j;

	for (int i = 0; i < j; i++)
	{
		s = new DbLinkNode;
		cin >> s->data;
		InsertDbLink_front(L, s);
	}
	DbLink_Print(L);
	
	//尾插
	int z;

	cout << "请输入你要插入的个数:";
	cin >> z;

	for (int i = 0; i < z; i++)
	{
		a = new DbLinkNode;
		cin >> a->data;
		InsertDbLink_front(L, a);
	}
	DbLink_Print(L);

	//任意位置插入
	int element, w;

	cout << "请输入你要插入的数:";
	cin >> w;

	cout << "请输入你要插入的位置:";
	cin >> element;

	DbLink_Insert(L, element, w);
	DbLink_Print(L);


	//查找元素
	int b;

	cout << "请输入你要查找元素的位置:";
	cin >> b;

	seekElem(L, b, element);
	cout << element << endl;

	//删除指定位置的元素
	
	DbLink_Delete(L, 3);
	DbLink_Print(L);

	//销毁链表
	DestroyLink(L);
	DbLink_Print(L);

	system("pause");
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会飞的鱼-blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值