数据结构第四篇——线性表的链式存储之双向链表

Posted T丶jl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构第四篇——线性表的链式存储之双向链表相关的知识,希望对你有一定的参考价值。

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

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

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

双向链表结构定义如下:

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

在双向链表中,若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、

以上是关于数据结构第四篇——线性表的链式存储之双向链表的主要内容,如果未能解决你的问题,请参考以下文章

线性表---链式存储(双向链表)

数据结构第五篇——线性表的链式存储之循环链表

线性表的Java实现--链式存储(双向链表)

线性表的链式存储结构(链表)

第三章 线性表---链式存储结构(双向链表)

双向链式线性表(模板实现)