目录
0基础概念
单向链表中,只有后驱指针,没有前驱指针
在单向和循环链表的基础上,增加了前驱指针 ,使得整个链表更加的灵活。
具体操作代码如下:
1链表结构
以上就是双向链表的原理图
1.1链表结点的基本内容(链表结点类型结构体):
//链表
struct DoubleLinked
{
DoubleLinked * prior;//增加前驱指针
DoubleLinked * next;
};
对比以前,此版本增加了前驱指针,prior
1.2头结点内容:
//链表性质
struct DoubleLinkedProperty
{
DoubleLinked header;
int size;
};
除了头结点中的头指针外(hearer.next) ,还有链表大小。
注意: 头结点,最好是DoubleLink类型,因为头结点不存放任何的插入元素,只是在内存中占用一块地址就行
让整个链表有起始点,方便进行各类操作的产物,如果定义为DoubleLink * 类型,这个指针无法指向任何内容,失去了指针的意义。
1.3用户数据结构(插入元素的数据结构)
typedef struct DoubleLinkedData
{
DoubleLinked node;
QString name;
int age;
}DLD;
用户自定义类型中,要求第一个成员必须是DoubleLink类型(链表结点类型结构体变量 )
为了更好的开发和应用分离,就是面对对象编程
在开发过程中不知道用户会传递什么样的数据进来,为了让用户传递任何类型的数据进来,程序都能应对,采用如此办法。
下面通过一个例子对上述数据结构的设置做出解释:
.h
//链表节点数据类型
struct LinkContent
{
struct LinkContent * next;
};
//链表数据类型
struct LinkProperty
{
struct LinkContent Content;
int size;
};
typedef void * LinkListTwo;//为了更好的让用户理解函数
typedef struct Test
{
LinkContent node;
QString name;
int age;
}T;
数据结构和上述相同(只是部分变量名称进行了替换)
.cpp 具体操作如下:
T t1 = {nullptr,"1",10};
T t2 = {nullptr,"2",20};
T t3 = {nullptr,"3",30};
T t4 = {nullptr,"4",40};
T t5 = {nullptr,"5",50};
qDebug()<<"初始化结果:"<<t1.node.next;
qDebug()<<"初始化结果:"<<t2.node.next;
qDebug()<<"初始化结果:"<<t3.node.next;
qDebug()<<"初始化结果:"<<t4.node.next;
qDebug()<<"初始化结果:"<<t5.node.next;
首先是初始化,我们可以看见,链表中的next指针目前全部都被初始化为空了
qDebug()<<"t1首地址:"<<&t1;
qDebug()<<"t2首地址:"<<&t2;
qDebug()<<"t3首地址:"<<&t3;
qDebug()<<"t4首地址:"<<&t4;
qDebug()<<"t5首地址:"<<&t5;
LinkContent *myContent1 = (LinkContent*)(&t1);
LinkContent *myContent2 = (LinkContent*)(&t2);
LinkContent *myContent3 = (LinkContent*)(&t3);
LinkContent *myContent4 = (LinkContent*)(&t4);
LinkContent *myContent5 = (LinkContent*)(&t5);
myContent1->next = myContent2;
myContent2->next = myContent3;
myContent3->next = myContent4;
myContent4->next = myContent5;
myContent5->next = nullptr;
之后我们取出插入元素的首地址
并将其强制转换类型,转换为结构体第一个元素的类型
t1是T类型,取地址(&t1),变成了指针,指向结构体的第一个元素,也就是LinkContent类型的指针
这也就是为什么一定要强调把 链表结点类型结构体变量 定义在用户自定义结构体中第一位的原因
强转后,就可以访问到每个要插入数据的next指针了,然后直接进行赋值操作
之后进行输出,并对比输出内容
qDebug()<<"强转类型后t1.node.next:"<<t1.node.next;
qDebug()<<"强转类型后t2.node.next:"<<t2.node.next;
qDebug()<<"强转类型后t3.node.next:"<<t3.node.next;
qDebug()<<"强转类型后t4.node.next:"<<t4.node.next;
qDebug()<<"强转类型后t5.node.next:"<<t5.node.next;
可见,要插入元素之间的连接已经完成,那么以上只是演示
言外之意是,在开发者眼里,不管用户自定义类型有多少个成员变量,只要第一个成员变量是链表结点类型结构体变量,在开发者写各类接口的时候,直接将传入接口的参数强制转换成链表结点类型结构体变量即可,然后就可以完成链表元素之间的连接。
到时候只需要给用户提供:
- 链表结点类型结构体名称
- 头结点结构体名称(初始化和调用接口的时候用)
- 各个接口名称和输入要求
即可
做到了面向对象编程的基本要求
2初始化和销毁
typedef void * DLHeader;
为了让用户更好理解,增加可读性。
初始化过程中,需要先堆上要一部分内存空间
在new和malloc之间,选择原则很简单,需要扩容,用malloc,就像动态数组,及线性表的顺序存储,用malloc显然更好操作:
数据结构:线性表-动态数组:https://blog.csdn.net/qq_41605114/article/details/104315027
C/C++:细说new与malloc的10点区别 :https://blog.csdn.net/qq_41605114/article/details/104342587
//初始化
DLHeader Inite_DL()
{
DoubleLinkedProperty * MyList = new DoubleLinkedProperty;
MyList->size = 0;
MyList->header.next = &(MyList->header);//为了后续的操作,此处必须指向自己
MyList->header.prior = &(MyList->header);
return MyList;
}
初始化一定要注意:
因为只有一个头结点,所以前驱(MyList->header.prior = &(MyList->header);)
后驱(MyList->header.next = &(MyList->header);)
都指向自己,及头结点(&(MyList->header))
销毁也是一样的
//销毁
void Destroy_DL(DLHeader DL)
{
if(nullptr == DL)
return;
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
delete MyDoubleLinked;
}
3插入
链表的插入,整体上的思路都是找到要插入位置的上一个位置,进行插入操作,在循环链表和双向链表中,
因为能够非常简单的访问到尾部指针,所以插入要分情况讨论,完整代码如下:
//插入
void Insert_DL(DLHeader DL,int place,void * data)
{
if(nullptr == DL)
return;
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
DoubleLinked * InserDATA = (DoubleLinked *)data;
DoubleLinked * pCurrent = &(MyDoubleLinked->header);
if(place>MyDoubleLinked->size)//最后插入
{
DoubleLinked * pEnd = (DoubleLinked *)MyDoubleLinked->header.prior;
pEnd->next = InserDATA;//最后元素的后驱
InserDATA->prior = pEnd;//要插入元素的前驱
MyDoubleLinked->header.prior = InserDATA;//头指针的前驱
InserDATA->next = &(MyDoubleLinked->header);//新的队尾,后驱指向头指针
MyDoubleLinked->size++;
}
else//中间插入
{
//找插入位置的前一个位置
for(int i = 0;i<place-1;++i)
{
pCurrent = pCurrent->next;
}
InserDATA->prior = pCurrent;//新插入的前驱赋值
pCurrent->next->prior = InserDATA;//被替换的元素的前驱赋值
InserDATA->next = pCurrent->next;//新插入元素后驱赋值
pCurrent->next = InserDATA;//前一个位置元素的后驱赋值
MyDoubleLinked->size++;
}
}
3.1从尾部插入:
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
DoubleLinked * InserDATA = (DoubleLinked *)data;
DoubleLinked * pCurrent = &(MyDoubleLinked->header);
if(place>MyDoubleLinked->size)//最后插入
{
DoubleLinked * pEnd = (DoubleLinked *)MyDoubleLinked->header.prior;
pEnd->next = InserDATA;//最后元素的后驱
InserDATA->prior = pEnd;//要插入元素的前驱
MyDoubleLinked->header.prior = InserDATA;//头指针的前驱
InserDATA->next = &(MyDoubleLinked->header);//新的队尾,后驱指向头指针
MyDoubleLinked->size++;
}
因为头结点的前驱,就是尾部结点,所以非常方便就可以定位到尾部结点:
DoubleLinked * pEnd = (DoubleLinked *)MyDoubleLinked->header.prior;
pEnd->next = InserDATA;//最后结点的后驱
- 将原尾部元素的后驱指针指向新插入的元素。
- 然后新插入的元素的前驱指向原尾部元素
- 之后更新头结点的前驱,指向新元素
- 最后更新新插入元素的后驱,一定要给头结点
完成插入:
3.1从中间插入
//插入
void Insert_DL(DLHeader DL,int place,void * data)
{
if(nullptr == DL)
return;
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
DoubleLinked * InserDATA = (DoubleLinked *)data;
DoubleLinked * pCurrent = &(MyDoubleLinked->header);
if(place>MyDoubleLinked->size)//最后插入
{
...
}
else//中间插入
{
//找插入位置的前一个位置
for(int i = 0;i<place-1;++i)
{
pCurrent = pCurrent->next;
}
InserDATA->prior = pCurrent;//新插入的前驱赋值
pCurrent->next->prior = InserDATA;//被替换的元素的前驱赋值
InserDATA->next = pCurrent->next;//新插入元素后驱赋值
pCurrent->next = InserDATA;//前一个位置元素的后驱赋值
MyDoubleLinked->size++;
}
}
从头结点开始遍历,找到要插入位置的前一个元素
- 将新插入的结点的前驱指向插入位置的前一个结点(PCurrent)
- 插入位置的后一个结点(PCurrent->next)的前驱指向新插入的结点
- 新插入的结点的后驱指向插入位置的后一个结点(PCurrent->next)
- 插入位置的前一个结点(PCurrent)的后驱指向新插入的结点
完成插入
整个插入过程,不论是循环链表还是双向链表,都很相似,把握好插入原则即可完成。
4遍历
//遍历
void Foreach_DL(DLHeader DL,int SizeMODE,void(*Print)(void *))//第二个参数是遍历的方向
{
if(nullptr == DL)
return;
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
if(SizeMODE == 1)//顺序打印
{
DoubleLinked * pCurrent = (DoubleLinked *)MyDoubleLinked->header.next;
while(pCurrent!=&(MyDoubleLinked->header))
{
Print(pCurrent);
pCurrent = pCurrent->next;
}
}
else if(SizeMODE == 0)//逆序打印
{
DoubleLinked * pEND = (DoubleLinked *)MyDoubleLinked->header.prior;
while(pEND!=&(MyDoubleLinked->header))
{
Print(pEND);
pEND = pEND->prior;
}
}
}
因为双向链表的性质,可以从头和尾分别出发,进行顺序遍历和逆序遍历
两种遍历方法:
顺序:
- 起点:第一个结点(&(MyDoublelinked->hearder.next))
- 终点:头指针(&(MyDoublelinked->hearder))
逆序:
- 起点:第一个结点(&(MyDoublelinked->hearder.prior))
- 终点:头指针(&(MyDoublelinked->hearder))
因为开发过程中不知道用户输入的数据类型,所以输出部分需要用户写一个回调函数:
回调函数:
void PrintDATA_DL(void * data)
{
if(nullptr == data)
return;
DLD * DATA = (DLD *)data;
qDebug()<<DATA->age<<DATA->name;
}
5删除
//按照位置删除
void Delete_DL(DLHeader DL,int place)
{
if(nullptr == DL)
return;
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
if(place <= 0)
return;
if(place > MyDoubleLinked->size)
return;
DoubleLinked * pCurrent = &(MyDoubleLinked->header);//
DoubleLinked * pDel = nullptr;//从第一个元素开始
for(int i = 0;i<place - 1;++i)
{
pCurrent = pCurrent->next;
}
pDel = pCurrent->next;//要删除的位置A
pCurrent->next = pDel->next;//更新要删除位置前一个元素的后驱
pDel->next->prior = pCurrent;//更新要删除元素后一个元素的前驱
pDel->next = nullptr;//删除元素操作
pDel->prior = nullptr;
MyDoubleLinked->size--;
}
更新要删除元素的前后驱,均设置为nullptr
更新删除元素前后相邻元素的后驱、前驱即可
pDel = pCurrent->next;//要删除的位置A
pCurrent->next = pDel->next;//更新要删除位置前一个元素的后驱
pDel->next->prior = pCurrent;//更新要删除元素后一个元素的前驱
pDel->next = nullptr;//删除元素操作
pDel->prior = nullptr;
程序验证
qDebug()<<"/*****************************进入双向链表部分*****************************/";
qDebug()<<"初始化";
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )Inite_DL();
DLD dld1 = {{nullptr,nullptr},"d111",1};
DLD dld2 = {{nullptr,nullptr},"d222",2};
DLD dld3 = {{nullptr,nullptr},"d333",3};
DLD dld4 = {{nullptr,nullptr},"d444",4};
DLD dld5 = {{nullptr,nullptr},"d555",5};
DLD dld6 = {{nullptr,nullptr},"d666",6};
qDebug()<<"插入元素";
Insert_DL(MyDoubleLinked,1,&dld1);
Insert_DL(MyDoubleLinked,2,&dld2);
Insert_DL(MyDoubleLinked,3,&dld3);
Insert_DL(MyDoubleLinked,4,&dld4);
Insert_DL(MyDoubleLinked,5,&dld5);
Insert_DL(MyDoubleLinked,6,&dld6);
qDebug()<<"顺序遍历";
Foreach_DL(MyDoubleLinked,1,PrintDATA_DL);
qDebug()<<"逆序遍历";
Foreach_DL(MyDoubleLinked,0,PrintDATA_DL);
因为双向链表的特性,所以可以进行顺序和逆序两种方式的遍历
qDebug()<<"&(MyDoubleLinked->header)"<<&(MyDoubleLinked->header)<<"dld1.node.prior"<<dld1.node.prior
<<"dld1.node.next"<<dld1.node.next<<"&(dld2.node)"<<&(dld2.node);
qDebug()<<"&(dld1.node)"<<&(dld1.node)<<"dld2.node.prior"<<dld2.node.prior
<<"dld2.node.next"<<dld2.node.next<<"&(dld3.node)"<<&(dld3.node);
qDebug()<<"&(dld2.node)"<<&(dld2.node)<<"dld3.node.prior"<<dld3.node.prior
<<"dld3.node.next"<<dld3.node.next<<"&(dld4.node)"<<&(dld4.node);
qDebug()<<"&(dld3.node)"<<&(dld3.node)<<"dld4.node.prior"<<dld4.node.prior
<<"dld4.node.next"<<dld4.node.next<<"&(dld5.node)"<<&(dld5.node);
qDebug()<<"&(dld4.node)"<<&(dld4.node)<<"dld5.node.prior"<<dld5.node.prior
<<"dld5.node.next"<<dld5.node.next<<"&(dld6.node)"<<&(dld6.node);
qDebug()<<"&(dld6.node)"<<&(dld6.node)<<"MyDoubleLinked->header.prior"<<MyDoubleLinked->header.prior
<<"MyDoubleLinked->header.next"<<MyDoubleLinked->header.next<<"&(dld1.node)"<<&(dld1.node);
qDebug()<<"个数:"<<Size_DL(MyDoubleLinked);
从输入元素的next和prior指针也可以看出,插入成功
qDebug()<<"删除第三个元素";
Delete_DL(MyDoubleLinked,3);
qDebug()<<"顺序遍历";
Foreach_DL(MyDoubleLinked,1,PrintDATA_DL);
qDebug()<<"逆序遍历";
Foreach_DL(MyDoubleLinked,0,PrintDATA_DL);
qDebug()<<"个数:"<<Size_DL(MyDoubleLinked);
qDebug()<<"删除dld5";
DeleteItem_DL(MyDoubleLinked,&dld5);
qDebug()<<"顺序遍历";
Foreach_DL(MyDoubleLinked,1,PrintDATA_DL);
qDebug()<<"逆序遍历";
Foreach_DL(MyDoubleLinked,0,PrintDATA_DL);
qDebug()<<"个数:"<<Size_DL(MyDoubleLinked);
qDebug()<<"插入:位置1,2";
Insert_DL(MyDoubleLinked,1,&dld3);
Insert_DL(MyDoubleLinked,2,&dld5);
qDebug()<<"顺序遍历";
Foreach_DL(MyDoubleLinked,1,PrintDATA_DL);
qDebug()<<"逆序遍历";
Foreach_DL(MyDoubleLinked,0,PrintDATA_DL);
qDebug()<<"个数:"<<Size_DL(MyDoubleLinked);
此部分主要是测试删除和插入
qDebug()<<"清除";
DLear_DL(MyDoubleLinked);
qDebug()<<"个数:"<<Size_DL(MyDoubleLinked);
qDebug()<<"&(MyDoubleLinked->header)"<<&(MyDoubleLinked->header)<<"dld1.node.prior"<<dld1.node.prior
<<"dld1.node.next"<<dld1.node.next<<"&(dld2.node)"<<&(dld2.node);
qDebug()<<"&(dld1.node)"<<&(dld1.node)<<"dld2.node.prior"<<dld2.node.prior
<<"dld2.node.next"<<dld2.node.next<<"&(dld3.node)"<<&(dld3.node);
qDebug()<<"&(dld2.node)"<<&(dld2.node)<<"dld3.node.prior"<<dld3.node.prior
<<"dld3.node.next"<<dld3.node.next<<"&(dld4.node)"<<&(dld4.node);
qDebug()<<"&(dld3.node)"<<&(dld3.node)<<"dld4.node.prior"<<dld4.node.prior
<<"dld4.node.next"<<dld4.node.next<<"&(dld5.node)"<<&(dld5.node);
qDebug()<<"&(dld4.node)"<<&(dld4.node)<<"dld5.node.prior"<<dld5.node.prior
<<"dld5.node.next"<<dld5.node.next<<"&(dld6.node)"<<&(dld6.node);
qDebug()<<"&(dld6.node)"<<&(dld6.node)<<"MyDoubleLinked->header.prior"<<MyDoubleLinked->header.prior
<<"MyDoubleLinked->header.next"<<MyDoubleLinked->header.next<<"&(dld1.node)"<<&(dld1.node);
qDebug()<<"销毁";
Destroy_DL(MyDoubleLinked);
最后这个部分是测试清除
附录
.h
#ifndef DOUBLELINKEDLIST_H
#define DOUBLELINKEDLIST_H
#include <QWidget>
#include<QDebug>
class DoubleLinkedList : public QWidget
{
Q_OBJECT
public:
explicit DoubleLinkedList(QWidget *parent = nullptr);
signals:
public slots:
};
//链表
struct DoubleLinked
{
DoubleLinked * prior;//增加前驱指针
DoubleLinked * next;
};
//链表性质
struct DoubleLinkedProperty
{
DoubleLinked header;//不能是指针,链表的第一个位置是空,不放任何元素,如果变成指针的话,指针无法指向头文件,因为头文件还没有被创建,逻辑上不合理
int size;
};
//包含数据的内容
typedef struct DoubleLinkedData
{
DoubleLinked node;
QString name;
int age;
}DLD;
typedef void * DLHeader;
//初始化
DLHeader Inite_DL();
//插入
void Insert_DL(DLHeader DL,int place,void * data);
//遍历
void Foreach_DL(DLHeader DL,int SizeMODE,void(*Print)(void *));//第二个参数是遍历的遍数
//打印函数
void PrintDATA_DL(void * data);
//按照位置删除
void Delete_DL(DLHeader DL,int place);
//按照元素删除
void DeleteItem_DL(DLHeader DL,void * data);
//销毁
void Destroy_DL(DLHeader DL);
//清空
void DLear_DL(DLHeader DL);
//个数
int Size_DL(DLHeader DL);
#endif // DOUBLELINKEDLIST_H
.cpp
#include "doublelinkedlist.h"
DoubleLinkedList::DoubleLinkedList(QWidget *parent) : QWidget(parent)
{
qDebug()<<"/*****************************进入双向链表部分*****************************/";
qDebug()<<"初始化";
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )Inite_DL();
DLD dld1 = {{nullptr,nullptr},"d111",1};
DLD dld2 = {{nullptr,nullptr},"d222",2};
DLD dld3 = {{nullptr,nullptr},"d333",3};
DLD dld4 = {{nullptr,nullptr},"d444",4};
DLD dld5 = {{nullptr,nullptr},"d555",5};
DLD dld6 = {{nullptr,nullptr},"d666",6};
qDebug()<<"插入元素";
Insert_DL(MyDoubleLinked,1,&dld1);
Insert_DL(MyDoubleLinked,2,&dld2);
Insert_DL(MyDoubleLinked,3,&dld3);
Insert_DL(MyDoubleLinked,4,&dld4);
Insert_DL(MyDoubleLinked,5,&dld5);
Insert_DL(MyDoubleLinked,6,&dld6);
qDebug()<<"顺序遍历";
Foreach_DL(MyDoubleLinked,1,PrintDATA_DL);
qDebug()<<"逆序遍历";
Foreach_DL(MyDoubleLinked,0,PrintDATA_DL);
qDebug()<<"&(MyDoubleLinked->header)"<<&(MyDoubleLinked->header)<<"dld1.node.prior"<<dld1.node.prior
<<"dld1.node.next"<<dld1.node.next<<"&(dld2.node)"<<&(dld2.node);
qDebug()<<"&(dld1.node)"<<&(dld1.node)<<"dld2.node.prior"<<dld2.node.prior
<<"dld2.node.next"<<dld2.node.next<<"&(dld3.node)"<<&(dld3.node);
qDebug()<<"&(dld2.node)"<<&(dld2.node)<<"dld3.node.prior"<<dld3.node.prior
<<"dld3.node.next"<<dld3.node.next<<"&(dld4.node)"<<&(dld4.node);
qDebug()<<"&(dld3.node)"<<&(dld3.node)<<"dld4.node.prior"<<dld4.node.prior
<<"dld4.node.next"<<dld4.node.next<<"&(dld5.node)"<<&(dld5.node);
qDebug()<<"&(dld4.node)"<<&(dld4.node)<<"dld5.node.prior"<<dld5.node.prior
<<"dld5.node.next"<<dld5.node.next<<"&(dld6.node)"<<&(dld6.node);
qDebug()<<"&(dld6.node)"<<&(dld6.node)<<"MyDoubleLinked->header.prior"<<MyDoubleLinked->header.prior
<<"MyDoubleLinked->header.next"<<MyDoubleLinked->header.next<<"&(dld1.node)"<<&(dld1.node);
qDebug()<<"个数:"<<Size_DL(MyDoubleLinked);
qDebug()<<"删除第三个元素";
Delete_DL(MyDoubleLinked,3);
qDebug()<<"顺序遍历";
Foreach_DL(MyDoubleLinked,1,PrintDATA_DL);
qDebug()<<"逆序遍历";
Foreach_DL(MyDoubleLinked,0,PrintDATA_DL);
qDebug()<<"个数:"<<Size_DL(MyDoubleLinked);
qDebug()<<"删除dld5";
DeleteItem_DL(MyDoubleLinked,&dld5);
qDebug()<<"顺序遍历";
Foreach_DL(MyDoubleLinked,1,PrintDATA_DL);
qDebug()<<"逆序遍历";
Foreach_DL(MyDoubleLinked,0,PrintDATA_DL);
qDebug()<<"个数:"<<Size_DL(MyDoubleLinked);
qDebug()<<"插入:位置1,2";
Insert_DL(MyDoubleLinked,1,&dld3);
Insert_DL(MyDoubleLinked,2,&dld5);
qDebug()<<"顺序遍历";
Foreach_DL(MyDoubleLinked,1,PrintDATA_DL);
qDebug()<<"逆序遍历";
Foreach_DL(MyDoubleLinked,0,PrintDATA_DL);
qDebug()<<"个数:"<<Size_DL(MyDoubleLinked);
qDebug()<<"清除";
DLear_DL(MyDoubleLinked);
qDebug()<<"个数:"<<Size_DL(MyDoubleLinked);
qDebug()<<"&(MyDoubleLinked->header)"<<&(MyDoubleLinked->header)<<"dld1.node.prior"<<dld1.node.prior
<<"dld1.node.next"<<dld1.node.next<<"&(dld2.node)"<<&(dld2.node);
qDebug()<<"&(dld1.node)"<<&(dld1.node)<<"dld2.node.prior"<<dld2.node.prior
<<"dld2.node.next"<<dld2.node.next<<"&(dld3.node)"<<&(dld3.node);
qDebug()<<"&(dld2.node)"<<&(dld2.node)<<"dld3.node.prior"<<dld3.node.prior
<<"dld3.node.next"<<dld3.node.next<<"&(dld4.node)"<<&(dld4.node);
qDebug()<<"&(dld3.node)"<<&(dld3.node)<<"dld4.node.prior"<<dld4.node.prior
<<"dld4.node.next"<<dld4.node.next<<"&(dld5.node)"<<&(dld5.node);
qDebug()<<"&(dld4.node)"<<&(dld4.node)<<"dld5.node.prior"<<dld5.node.prior
<<"dld5.node.next"<<dld5.node.next<<"&(dld6.node)"<<&(dld6.node);
qDebug()<<"&(dld6.node)"<<&(dld6.node)<<"MyDoubleLinked->header.prior"<<MyDoubleLinked->header.prior
<<"MyDoubleLinked->header.next"<<MyDoubleLinked->header.next<<"&(dld1.node)"<<&(dld1.node);
qDebug()<<"销毁";
Destroy_DL(MyDoubleLinked);
}
//初始化
DLHeader Inite_DL()
{
DoubleLinkedProperty * MyList = new DoubleLinkedProperty;
MyList->size = 0;
MyList->header.next = &(MyList->header);//为了后续的操作,此处必须指向自己
MyList->header.prior = &(MyList->header);
return MyList;
}
//插入
void Insert_DL(DLHeader DL,int place,void * data)
{
if(nullptr == DL)
return;
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
DoubleLinked * InserDATA = (DoubleLinked *)data;
DoubleLinked * pCurrent = &(MyDoubleLinked->header);
if(place>MyDoubleLinked->size)//最后插入
{
DoubleLinked * pEnd = (DoubleLinked *)MyDoubleLinked->header.prior;
pEnd->next = InserDATA;//最后元素的后驱
InserDATA->prior = pEnd;//要插入元素的前驱
MyDoubleLinked->header.prior = InserDATA;//头指针的前驱
InserDATA->next = &(MyDoubleLinked->header);//新的队尾,后驱指向头指针
MyDoubleLinked->size++;
}
else//中间插入
{
//找插入位置的前一个位置
for(int i = 0;i<place-1;++i)
{
pCurrent = pCurrent->next;
}
InserDATA->prior = pCurrent;//新插入的前驱赋值
pCurrent->next->prior = InserDATA;//被替换的元素的前驱赋值
InserDATA->next = pCurrent->next;//新插入元素后驱赋值
pCurrent->next = InserDATA;//前一个位置元素的后驱赋值
MyDoubleLinked->size++;
}
}
//遍历
void Foreach_DL(DLHeader DL,int SizeMODE,void(*Print)(void *))//第二个参数是遍历的方向
{
if(nullptr == DL)
return;
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
if(SizeMODE == 1)//顺序打印
{
DoubleLinked * pCurrent = (DoubleLinked *)MyDoubleLinked->header.next;
while(pCurrent!=&(MyDoubleLinked->header))
{
Print(pCurrent);
pCurrent = pCurrent->next;
}
}
else if(SizeMODE == 0)//逆序打印
{
DoubleLinked * pEND = (DoubleLinked *)MyDoubleLinked->header.prior;
while(pEND!=&(MyDoubleLinked->header))
{
Print(pEND);
pEND = pEND->prior;
}
}
}
//打印函数
void PrintDATA_DL(void * data)
{
if(nullptr == data)
return;
DLD * DATA = (DLD *)data;
qDebug()<<DATA->age<<DATA->name;
}
//按照位置删除
void Delete_DL(DLHeader DL,int place)
{
if(nullptr == DL)
return;
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
if(place <= 0)
return;
if(place > MyDoubleLinked->size)
return;
DoubleLinked * pCurrent = &(MyDoubleLinked->header);//
DoubleLinked * pDel = nullptr;//从第一个元素开始
for(int i = 0;i<place - 1;++i)
{
pCurrent = pCurrent->next;
}
pDel = pCurrent->next;//要删除的位置A
pCurrent->next = pDel->next;//更新要删除位置前一个元素的后驱
pDel->next->prior = pCurrent;//更新要删除元素后一个元素的前驱
pDel->next = nullptr;//删除元素操作
pDel->prior = nullptr;
MyDoubleLinked->size--;
}
//按照元素删除
void DeleteItem_DL(DLHeader DL,void * data)
{
if(nullptr == DL)
return;
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
DoubleLinked * pCurrent = MyDoubleLinked->header.next;//
DoubleLinked * pInserData = (DoubleLinked *)data;//
int place = 1;
while(pCurrent!=&(MyDoubleLinked->header))
{
if(pCurrent == pInserData)
{
Delete_DL(DL,place);
break;
}
place++;
pCurrent = pCurrent->next;
}
}
//销毁
void Destroy_DL(DLHeader DL)
{
if(nullptr == DL)
return;
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
delete MyDoubleLinked;
}
//清空
void DLear_DL(DLHeader DL)
{
if(nullptr == DL)
return;
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
DoubleLinked * pCurrent = MyDoubleLinked->header.next;//从第一个元素开始
DoubleLinked * pCut = nullptr;//从第一个元素开始
while(pCurrent!=&(MyDoubleLinked->header))
{
pCut = pCurrent;
pCurrent = pCurrent->next;
pCut->prior = nullptr;
pCut->next = nullptr;
}
MyDoubleLinked->size =0;
MyDoubleLinked->header.next = &(MyDoubleLinked->header);
MyDoubleLinked->header.prior = &(MyDoubleLinked->header);
}
//个数
int Size_DL(DLHeader DL)
{
if(nullptr == DL)
return 0;
DoubleLinkedProperty * MyDoubleLinked = (DoubleLinkedProperty * )DL;
return MyDoubleLinked->size;
}