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();
}