C++双向链表浅析

C++双向链表浅析

双向链表简介

双向链表又称双链表,是链表的一种。

从名字来看,我们就知道它的结点结构体不同于单链表只有后继,双向链表的结点结构体除了有后继结点之外,还有前驱结点,前驱结点的引入设计就使得双向链表的灵活度和可操作性大大增加,可以正向操作,也可以通过前驱结点逆向操作,

我在实现这个双向链表时一开始是按照书上的方法进行操练做,可是书上的实现方法晦涩难懂且报错频出,那么不妨按自己的思想进行设计实现!

结点结构体的设计

//双向链表结点结构体的定义  当然 亦可以把结构体定义成类
struct DulNode
{
	int data;
	DulNode* prior;    //前驱结点
	DulNode* next;     //后继结点
};

也可以设置成结点类,大同小异

双向链表类的设计

//双向链表类的定义
//双向链表的工作机制和单链表类似
//通过工作指针来对链表进行操作
class DoubleLink
{
public:
	DoubleLink(int a[],int length);  //创建双向链表
	~DoubleLink();     //析构双向链表
	void TravelListOrder();  //正向遍历链表
	void TravelListRetu();   //逆向遍历链表
	void sortList();         //冒泡排序  正在实现
	void ChangeList(int num, int position);  //修改指定位置的值
	void Insert(int num, int position);  //向指定位置插入值
	void Clear();  //清空链表  其实相当于析构函数
	void DeleteItem(int position);   //删除指定位置的结点
	int Get(int position);   //查找指定位置的值

private:
	DulNode* pHead;   //头结点
	DulNode* pTail;   //尾结点
	int length;
};

构造双向链表

//双向链表的构造初始化  传一个数组及其大小
DoubleLink::DoubleLink(int a[],int length)
{
	this->length = length;
	pHead = new DulNode;
	pHead->prior = NULL;
	pTail = pHead;
	for (int i = 0; i < length; i++)
	{
		DulNode* temp = new DulNode;  //临时结点
		temp->data = a[i];   //临时结点储存数组 的值
		temp->next = NULL;   //在这里临时节点即是最后结点  所以下一结点为空
		temp->prior = pTail; //前一结点即为上一次的尾结点
		pTail->next = temp;  //尾节点的下一个即为现在的临时结点
		pTail = temp;     //将临时节点赋给尾结点
	}
	cout << "头结点" << pHead << endl;
	cout << "终端结点的后继" << pTail->next << endl;;

	//看不懂的话 自己按流程走一遍就好了
}

析构

DoubleLink::~DoubleLink()
{
	//析构函数
	DulNode* q;   //定义工作指针
	DulNode* p = pHead->next;  //从头结点的下一个 也就是链表的第一个元素开始
	while (p != NULL)
	{
		q = p;           //为工作指针赋值
		p = p->next;     //参考指针下移
		delete q;        //删除工作指针所指向的结点
	}
	p = NULL;           //删除结束后 为工作指针和参考指针赋空值
	q = NULL;
}

正向/逆向遍历

//正向遍历  就是从头指针开始  通过结点结构体中的next进行操作
void DoubleLink::TravelListOrder()
{
	DulNode* p = pHead->next;   //参考指针  从第一个有值结点开始
	while (p != NULL)    //当参考指针不为空时进行遍历输出操作
	{
		cout << p->data << " ";
		p = p->next;     //参考指针下移
	}
	cout << endl;
}
//逆向遍历  从尾结点开始  通过结点结构体中的prior指针进行操作
void DoubleLink::TravelListRetu()
{
	DulNode* p = pTail;    //参考指针  从尾结点开始
	while (p->prior != NULL)
	{
		cout << p->data << " ";
		p = p->prior;  //参考指针上移 逆向遍历输出嘛
	}
	cout << endl;
}

冒泡排序

//双向链表的冒泡排序
void DoubleLink::sortList()
{
	//其实和普通的冒泡排序算法类似 只是原本的遍历条件发生了更改
	DulNode* p = new DulNode;
	DulNode* q = new DulNode;
	int temp;   //临时变量用于保存值
	for (p = pHead->next; p->next != NULL; p = p->next)
	{
		for (q = p->next; q != NULL; q = q->next)
		{
			if (q->data < p->data)
			{
				temp = q->data;
				q->data = p->data;
				p->data = temp;
			}
		}
	}
}

改变数据

//改变指定位置的数据  这没啥讲的了 自己看看
void DoubleLink::ChangeList(int num, int position)
{
	DulNode* p = pHead->next;
	if (position > length || position <= 0)
	{
		cout << "Pos Error" << endl;
		return;
	}
	for (int i = 0; i < position - 1; i++)
	{
		p = p->next;
	}
	//前面的一堆操作就是为了找到你要改的那个位置的对应结点

	p->data = num;
}

插入算法

//插入算法
void DoubleLink::Insert(int num, int position)
{
	DulNode* p = pHead->next;
	if (position > length || position <= 0)
	{
		cout << "Pos Error" << endl;
		return;
	}
	for (int i = 0; i < position - 1; i++)
	{
		p = p->next;
	}
	//前面的一堆操作就是为了找到你要改的那个位置的对应结点

	//这一块和书本上有些类似了
	DulNode* temp = new DulNode;
	temp->data = num;
	temp->next = p;
	temp->prior = p->prior;
	p->prior->next = temp;
	p->prior = temp;
	length++;
}

完整代码

DoubleLink.h

#ifndef __DOUBLELINK__
#define __DOUBLELINK__

/*
* 防卫式声明
* Author:YiXing Liu
* Date:2021/8/16
* Des:DoubleLinkList By another method without any textbooks!
* 双向链表的自我实现
*/



#include<iostream>
using namespace std;

//双向链表结点结构体的定义  当然 亦可以把结构体定义成类
struct DulNode
{
	int data;
	DulNode* prior;    //前驱结点
	DulNode* next;     //后继结点
};

//双向链表的大部分操作和单链表类似
//只是多了前驱结点以辅助指向前一个指针

//双向链表类的定义
//双向链表的工作机制和单链表类似
//通过工作指针来对链表进行操作
class DoubleLink
{
public:
	DoubleLink(int a[],int length);  //创建双向链表
	~DoubleLink();     //析构双向链表
	void TravelListOrder();  //正向遍历链表
	void TravelListRetu();   //逆向遍历链表
	void sortList();         //冒泡排序  正在实现
	void ChangeList(int num, int position);  //修改指定位置的值
	void Insert(int num, int position);  //向指定位置插入值
	void Clear();  //清空链表  其实相当于析构函数
	void DeleteItem(int position);   //删除指定位置的结点
	int Get(int position);   //查找指定位置的值

private:
	DulNode* pHead;   //头结点
	DulNode* pTail;   //尾结点
	int length;
};
#endif

DoubleLink.cpp

#include "DoubleLink.h"

//pHead为双链表的头结点   pTail为双链表的尾结点
//结点结构体中 next为下一个  prior为上一个


//双向链表的构造初始化  传一个数组及其大小
DoubleLink::DoubleLink(int a[],int length)
{
	this->length = length;
	pHead = new DulNode;
	pHead->prior = NULL;
	pTail = pHead;
	for (int i = 0; i < length; i++)
	{
		DulNode* temp = new DulNode;  //临时结点
		temp->data = a[i];   //临时结点储存数组 的值
		temp->next = NULL;   //在这里临时节点即是最后结点  所以下一结点为空
		temp->prior = pTail; //前一结点即为上一次的尾结点
		pTail->next = temp;  //尾节点的下一个即为现在的临时结点
		pTail = temp;     //将临时节点赋给尾结点
	}
	cout << "头结点" << pHead << endl;
	cout << "终端结点的后继" << pTail->next << endl;;

	//看不懂的话 自己按流程走一遍就好了
}

DoubleLink::~DoubleLink()
{
	//析构函数
	DulNode* q;   //定义工作指针
	DulNode* p = pHead->next;  //从头结点的下一个 也就是链表的第一个元素开始
	while (p != NULL)
	{
		q = p;           //为工作指针赋值
		p = p->next;     //参考指针下移
		delete q;        //删除工作指针所指向的结点
	}
	p = NULL;           //删除结束后 为工作指针和参考指针赋空值
	q = NULL;
}

//正向遍历  就是从头指针开始  通过结点结构体中的next进行操作
void DoubleLink::TravelListOrder()
{
	DulNode* p = pHead->next;   //参考指针  从第一个有值结点开始
	while (p != NULL)    //当参考指针不为空时进行遍历输出操作
	{
		cout << p->data << " ";
		p = p->next;     //参考指针下移
	}
	cout << endl;
}

//逆向遍历  从尾结点开始  通过结点结构体中的prior指针进行操作
void DoubleLink::TravelListRetu()
{
	DulNode* p = pTail;    //参考指针  从尾结点开始
	while (p->prior != NULL)
	{
		cout << p->data << " ";
		p = p->prior;  //参考指针上移 逆向遍历输出嘛
	}
	cout << endl;
}

//双向链表的冒泡排序
void DoubleLink::sortList()
{
	//其实和普通的冒泡排序算法类似 只是原本的遍历条件发生了更改
	DulNode* p = new DulNode;
	DulNode* q = new DulNode;
	int temp;   //临时变量用于保存值
	for (p = pHead->next; p->next != NULL; p = p->next)
	{
		for (q = p->next; q != NULL; q = q->next)
		{
			if (q->data < p->data)
			{
				temp = q->data;
				q->data = p->data;
				p->data = temp;
			}
		}
	}
}

//改变指定位置的数据  这没啥讲的了 自己看看
void DoubleLink::ChangeList(int num, int position)
{
	DulNode* p = pHead->next;
	if (position > length || position <= 0)
	{
		cout << "Pos Error" << endl;
		return;
	}
	for (int i = 0; i < position - 1; i++)
	{
		p = p->next;
	}
	//前面的一堆操作就是为了找到你要改的那个位置的对应结点

	p->data = num;
}

//插入算法
void DoubleLink::Insert(int num, int position)
{
	DulNode* p = pHead->next;
	if (position > length || position <= 0)
	{
		cout << "Pos Error" << endl;
		return;
	}
	for (int i = 0; i < position - 1; i++)
	{
		p = p->next;
	}
	//前面的一堆操作就是为了找到你要改的那个位置的对应结点

	//这一块和书本上有些类似了
	DulNode* temp = new DulNode;
	temp->data = num;
	temp->next = p;
	temp->prior = p->prior;
	p->prior->next = temp;
	p->prior = temp;
	length++;
}

//和析构函数类似
void DoubleLink::Clear()
{
	DulNode* q;
	DulNode* p = pHead->next;
	while (p != NULL)
	{
		q = p;
		p = p->next;
		delete q;
	}
	p = NULL;
	q = NULL;
}


//整个算法类似
void DoubleLink::DeleteItem(int position)
{
	DulNode* p = pHead->next;
	if (position > length || position <= 0)
	{
		cout << "Pos Error" << endl;
		return;
	}
	for (int i = 0; i < position - 1; i++)
	{
		p = p->next;
	}
	p->prior->next = p->next;
	p->next->prior = p->prior;
	delete p;
	length--;
}

int DoubleLink::Get(int position)
{
	DulNode* p = pHead->next;
	if (position > length || position <= 0)
	{
		cout << "Pos Error" << endl;
		return 0;
	}
	for (int i = 0; i < position - 1; i++)
	{
		p = p->next;
	}
	return p->data;
}

main.cpp

#include "DoubleLink.h"

int main()
{
	int a[3] = { 1,4,2 };
	DoubleLink l(a,3);
	cout << "正向遍历" << endl;
	l.TravelListOrder();
	cout << "逆向遍历" << endl;
	l.TravelListRetu();
	cout << "插入测试" << endl;
	l.Insert(5, 3);
	l.TravelListOrder();
	cout << "删除测试" << endl;
	l.DeleteItem(3);
	l.TravelListOrder();
	cout << "排序测试" << endl;
	l.sortList();
	l.TravelListOrder();
}

测试

image-20210816150435746

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值