数据结构:双向链表

目录

0基础概念

1链表结构

1.1链表的基本内容(链表结点类型结构体):

1.2头结点内容:

1.3用户数据结构(插入元素的数据结构)

2初始化和销毁

3插入

3.1从尾部插入:

3.1从中间插入

4遍历

5删除

程序验证

附录


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;

可见,要插入元素之间的连接已经完成,那么以上只是演示

言外之意是,在开发者眼里,不管用户自定义类型有多少个成员变量,只要第一个成员变量是链表结点类型结构体变量,在开发者写各类接口的时候,直接将传入接口的参数强制转换成链表结点类型结构体变量即可,然后就可以完成链表元素之间的连接。

 

到时候只需要给用户提供: 

  1. 链表结点类型结构体名称
  2. 头结点结构体名称(初始化和调用接口的时候用)
  3. 各个接口名称和输入要求

即可

做到了面向对象编程的基本要求

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;//最后结点的后驱

  1. 原尾部元素的后驱指针指向新插入的元素
  2. 然后新插入的元素的前驱指向原尾部元素
  3. 之后更新头结点的前驱,指向新元素
  4. 最后更新新插入元素的后驱,一定要给头结点

完成插入:

           

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++;
    }

}

从头结点开始遍历,找到要插入位置的前一个元素

  1. 新插入的结点的前驱指向插入位置的前一个结点(PCurrent)
  2. 插入位置的后一个结点(PCurrent->next)的前驱指向新插入的结点
  3. 新插入的结点的后驱指向插入位置的后一个结点(PCurrent->next)
  4. 插入位置的前一个结点(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;
        }
    }
}

因为双向链表的性质,可以从头和尾分别出发,进行顺序遍历和逆序遍历

两种遍历方法:

顺序:

  1. 起点:第一个结点(&(MyDoublelinked->hearder.next))
  2. 终点:头指针(&(MyDoublelinked->hearder))

逆序:

  1. 起点:第一个结点(&(MyDoublelinked->hearder.prior))
  2. 终点:头指针(&(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;

}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值