zoukankan      html  css  js  c++  java
  • 数据结构第四篇——线性表的链式存储之双向链表

    ♥注:未经博主同意,不得转载。

      前面讨论的单链表,每个结点中只有一个指针域,用来存放指向后继结点的指针,因此,从某个结点出发只能顺时针往后查找其他结点。若要查找某个结点的直接前驱,则需要从头指针开始沿链表探寻,处理起来十分不方便。为克服单链表的这一缺点,可引入双向链表

      双向链表中每一个结点含有两个指针域,一个指针指向其直接前驱结点,另一个指针指向直接后继结点。和单链表类似,双向链表一般也只有头指针唯一确定;同样也可设头结点,使得双向链表的某些操作简便一些。

    双向链表结构定义如下:

       双向链表是一种对称结构,和单链表相比,虽然每个结点增加了一个指针域,多占用了空间,但这给操作的实现带来了方便。

    在双向链表中,若p为指向表中某一结点的指针,则显然有:

    p->next->prior=p->prior->next=p

    这个表达式恰当的反映了这种结构的特性。

    在双向链表中,有些操作如取元素、求表长、定位等,只涉及一个方向的指针,则这些操作的算法描述和单链表相同。但在进行插入、删除操作时有很大的不同,在双向链表中需同时修改两个方向上的指针,还要小心修改顺序。

    1.结点删除操作:

    删除结点p时,先从头结点开始搜索链表,找到p后做以下操作:

    p->prior->next=p->next;

    if(p->next)

    p->next->prior=p->prior;

    整个完整删除函数为:

     1 //删除操作
     2 Data DBList::Delete(int i)
     3 {
     4     DNode* p = head;
     5     int k=0;
     6     while(p&&k<i-1)                //将p指到要删除的位置
     7     {
     8         p=p->next;
     9         ++k;
    10     }
    11     if(!p||p->next==NULL)        //判断删除位置是否存在和是否有后继
    12     {
    13         cout<<"删除位置非法"<<endl;
    14         exit(0);
    15     }
    16     DNode* q = p->next;            //暂存删除结点
    17     
    18     p->prior->next=p->next;
    19     if(!p->next)
    20     p->next->prior=p->prior;
    21     
    22     Data e=q->data;                //将删除的元素储存起来
    23     delete q;                    //释放将要删除的结点
    24     return e;
    25 }

    2.结点插入操作:

    在结点p之前插入结点s,先从头结点开始搜索链表,找到p后做以下操作:

    s = new DNode;   //创建此结点

     s->data=e;     //将元素存入创建的结点
     s->prior=p->prior;
     p->prior->next=s;
     p->prior=s;
     s->next=p;

    整个完整插入函数为:

     1 //插入操作
     2 void DBList::Insert(Data x,int i)
     3 {
     4     DNode* p=head;
     5     int k=0;
     6     while(p&&k<i-1)            //    将p指到第i个位置
     7     {
     8         p=p->next;
     9         ++k;
    10     }
    11     if(!p||k>i-1)            //判断是否存在第i个元素
    12     {
    13         cout<<""<<i<<"个元素不存在"<<endl;
    14         exit(0);
    15     }
    16     DNode* s = new DNode;            //创建此结点
    17     if(!s)
    18     {
    19         cout<<"空间分配失败"<<endl;
    20         exit(0);
    21     }
    22     
    23     s->data=x;                    //将元素存入创建的结点
    24     s->prior=p->prior;
    25     p->prior->next=s; 
    26     p->prior=s;
    27     s->next=p;
    28 }

    3.创建双向链表:

     1 typedef int Data;
     2 
     3 struct DNode
     4 {
     5     Data data;            //数据
     6     DNode* prior;        //指向前驱的指针 
     7     DNode* next;        //指向后继的指针 
     8 };
     9 
    10 class DBList
    11 {
    12     DNode* head;                //创建头结点
    13     public:
    14     DBList()                //构造函数
    15     {
    16         head = new DNode;
    17         head->next = NULL;
    18         head->prior = NULL;
    19     }
    20     ~DBList();                        //析构函数
    21     
    22     Data GetElem(int i);                //取第i个元素的值
    23     bool IsEmpty();                        //判断是否为空链表
    24     void Create(Data* a , int n);        //创建长度为n的双链表(头插法)
    25     void Create1(Data* a , int n);        //创建长度为n的双链表(尾插法)
    26     DNode* Locate(Data e,int* i);        //查找值为e的结点,返回指向e的指针
    27     
    28     DNode* Prior(Data e);                //返回元素e的前驱 
    29     DNode* Prior1(int i);                //返回第i个元素的前驱 
    30     DNode* Next(Data e);                //返回元素e的后继 
    31     DNode* Next1(int i);                //返回第i个元素的后继
    32      
    33     void Insert(Data x,int i);            //将数据元素x插入到第i个位置
    34     Data Delete(int i);                    //删除第i个元素
    35     //int _Delete(Data e);                //删除值为e的第一个元素
    36     int Size();                            //返回链表的长度
    37     void Clear();                        //清空
    38     void Print();                        //正向显示元素
    39     void Print1();                        //逆向显示元素
    40 };

    这里是其他部分函数的实现:

      1 //计算链表长度
      2 int DBList::Size()
      3 {
      4     DNode* p;            //创建指针p
      5     int k;
      6     p=head->next;                //p指向第一个元素结点 
      7     k=0;
      8     while(p)
      9     {
     10         p=p->next;
     11         ++k;
     12     }
     13     return k;
     14 }
     15 
     16 //正向显示所有元素
     17 void DBList::Print()
     18 {
     19     DNode* p;            //创建指针p
     20     p=head->next;            //p指向第一个元素结点 
     21     while(p)    
     22     {
     23         cout<<p->data<<" ";
     24         p=p->next;
     25     }
     26     cout<<endl;
     27 }
     28 
     29 //逆向显示所有元素
     30 void DBList::Print1()
     31 {
     32     DNode* p;            //创建指针p
     33     p=head->next;            //p指向第一个元素结点 
     34     while(p)
     35     {
     36         if(p->next)
     37         p=p->next;
     38         else
     39         break;
     40     }    
     41     
     42     while(p)    
     43     {
     44         cout<<p->data<<" ";
     45         p=p->prior;
     46     }
     47     cout<<endl;
     48 }
     49 
     50 
     51 //取元素
     52 Data DBList::GetElem(int i)
     53 {
     54     if(head->next == NULL)            //为空链表
     55     {
     56         cout<<"此链表为空"<<endl;
     57         exit(0);
     58     }
     59     else
     60     {
     61         DNode* p;            //创建指针p
     62         int k;
     63         p=head;                //p指向头结点
     64         k=0;
     65         while(p&&k<i)        //p移到i的位置
     66         {
     67             p=p->next;
     68             k++;
     69         }
     70         if(!p||k>i)            //超出个数范围
     71         {
     72             cout<<""<<i<<"个元素不存在"<<endl;
     73             exit(0);
     74         }
     75         return (p->data);
     76     }
     77 }    //此算法的时间复杂度为O(n)
     78 
     79 //判断链表是否为空 
     80 bool DBList::IsEmpty()
     81 {
     82     if(head->next==NULL)
     83     {
     84         cout<<"此链表为空"<<endl;
     85         return true;
     86     }
     87     else
     88     {
     89         cout<<"此链表非空"<<endl;
     90         return false;
     91     }
     92 }
     93 
     94 //建立双链表
     95 //第一种是头插法
     96 void DBList::Create(Data* a,int n)
     97 {
     98     DNode* p=NULL;
     99     DNode* q=head;
    100     for(int i=n-1;i>=0;--i)
    101     {
    102         p=new DNode;                    //创建新结点
    103         p->data=a[i];                    //将元素存入结点
    104         
    105         q=p->prior;
    106         p->next=head->next;            //将新加入结点指向头结点后面
    107         head->next=p;                //将头结点指向新加入的结点
    108         q=p;
    109     }
    110 }
    111 
    112 //查找给定值的结点
    113 DNode* DBList::Locate(Data e,int *i)
    114 {
    115     *i=1;
    116     DNode* p=NULL;
    117     p=head->next;
    118     while(p)                        //p不为空
    119     {
    120         if(p->data==e)                //找到元素
    121             return p;
    122         else
    123         {
    124             p=p->next;
    125             ++(*i);
    126         }
    127     }
    128     cout<<"当前链表中无此元素"<<endl;
    129     exit(0);
    130     return NULL;
    131 }
    132 
    133 //清空双链表
    134 //保留表头结点,把双链表中的
    135 //其余所有结点全部释放。
    136 void DBList::Clear()
    137 {
    138     DNode* p=NULL;
    139     DNode* q=NULL;
    140     p=head->next;
    141     while(p)
    142     {
    143         q=p;
    144         p=p->next;
    145         delete q;
    146     }
    147     head->next = NULL;
    148     head->prior = NULL;
    149 }
    150 
    151 //析构函数
    152 //释放双链表中的所有元素。
    153 DBList::~DBList()
    154 {
    155     DNode* p;
    156     p=head;
    157     while(p)
    158     {
    159         p=p->next;
    160         delete head;
    161         head=p;
    162     }
    163 }

    其他操作请参考上篇文章的部分内容:http://www.cnblogs.com/tenjl-exv/p/7470075.html

    本次内容到这里就结束了。

    v、

  • 相关阅读:
    Linux 使用 github 常用命令
    配置使用 git 秘钥连接 GitHub
    Python 使用 face_recognition 人脸识别
    face_recognition 基础接口
    pycharm 安装激活操作
    Python 人工智能之人脸识别 face_recognition 模块安装
    Linux pip 命令无法使用问题
    vue 起步
    vue.JS 介绍
    AngularJS 简介
  • 原文地址:https://www.cnblogs.com/tenjl-exv/p/7475518.html
Copyright © 2011-2022 走看看