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

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

  链表是另一种形式的链式存储结构,它是线性链表的一种变形。在线性链表中,每个结点的指针都指向它的下一个结点,最后一个结点的指针域为空,表示链表的结束。若使最后一个结点的指针指向头结点,则链表呈环状,这样的链表称为循环链表

循环链表当然也分为单链表双向列表

通常情况下,在循环链表中设立尾指针而不设头指针,可使某些操作简化。

循环链表的定义和操作与单链表类似,只是循环结束条件有所不同,下面只给出单循环链表的定义和部分操作,至于双向循环链表可能会在以后的项目中出现,到时再进一步探讨。

单循环链表定义如下:

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

函数功能实现如下:

  1 //计算链表长度
  2 int CList::Size()
  3 {
  4     Node* p;            //创建指针p
  5     int k;
  6     p=head->next;        //p指向第一个元素结点
  7     k=0;
  8     while(p!=head)
  9     {
 10         p=p->next;
 11         ++k;
 12     }
 13     return k;
 14 }
 15
 16 //显示所有元素
 17 void CList::Print()
 18 {
 19     Node* p;                //创建指针p
 20     p=head->next;            //p指向第一个元素结点
 21     while(p!=head)
 22     {
 23         cout<<p->data<<" ";
 24         p=p->next;
 25     }
 26     cout<<endl;
 27 }
 28
 29 //取元素
 30 Data CList::GetElem(int i)
 31 {
 32     if(head->next == NULL)            //为空链表
 33     {
 34         cout<<"此链表为空"<<endl;
 35         exit(0);
 36     }
 37     else
 38     {
 39         Node* p;            //创建指针p
 40         int k;
 41         p=head;                //p指向头结点
 42         k=0;
 43         while(p&&k<i)        //p移到i的位置
 44         {
 45             p=p->next;
 46             k++;
 47         }
 48         return (p->data);
 49     }
 50 }    //此算法的时间复杂度为O(n)
 51
 52 //插入操作
 53 void CList::Insert(Data x,int i)
 54 {
 55     Node* p=head;
 56     int k=0;
 57     while(p&&k<i-1)            //    将p指到第i个位置
 58     {
 59         p=p->next;
 60         ++k;
 61
 62         if(p==head)
 63         p=p->next;
 64     }
 65     Node* s = new Node;            //创建此结点
 66     if(!s)
 67     {
 68         cout<<"空间分配失败"<<endl;
 69         exit(0);
 70     }
 71
 72     s->data=x;                    //将元素存入创建的结点
 73     s->next=p->next;
 74     p->next=s;
 75 }
 76
 77 //删除操作
 78 Data CList::Delete(int i)
 79 {
 80     Node* p = head;
 81     int k=0;
 82     while(p&&k<i-1)                //将p指到要删除的位置
 83     {
 84         p=p->next;
 85         ++k;
 86
 87         if(p==head)
 88         p=p->next;
 89     }
 90     Node* q = p->next;            //暂存删除结点
 91
 92     p->next = q->next;            //将结点隔离出来
 93     Data e=q->data;                //将删除的元素储存起来
 94     delete q;                    //释放将要删除的结点
 95     return e;
 96 }
 97
 98 //判断链表是否为空
 99 bool CList::IsEmpty()
100 {
101     if(head->next==NULL)
102     {
103         cout<<"此链表为空"<<endl;
104         return true;
105     }
106     else
107     {
108         cout<<"此链表非空"<<endl;
109         return false;
110     }
111 }
112
113 //建立单循环链表
114 //第一种是头插法
115 void CList::Create(Data* a,int n)
116 {
117     Node* p=NULL;
118     Node* q=NULL;
119     for(int i=n-1;i>=0;--i)
120     {
121         p=new Node;                    //创建新结点
122         p->data=a[i];                    //将元素存入结点
123
124         p->next=head->next;            //将新加入结点指向头结点后面
125         head->next=p;                //将头结点指向新加入的结点
126     }
127 }
128
129 //第二种是尾插法
130 void CList::Create1(Data* a,int n)
131 {
132     Node* p=NULL;
133     Node* q=head;                    //创建中间结点指针
134     for(int i=0;i<n;++i)
135     {
136         p=new Node;                    //创建储存元素的新结点
137         p->data=a[i];                //将元素存入创建的结点
138         p->next=q->next;            //插入到终端结点之后
139         q->next=p;                    //终端结点指向新建结点
140         q=p;                        //q指向新建结点
141     }
142     p->next=NULL;
143 }
144
145 //查找给定值的结点
146 Node* CList::Locate(Data e,int *i)
147 {
148     *i=1;
149     Node* p=head->next;
150
151     while(p!=head)                        //p不为空
152     {
153         if(p->data==e)                //找到元素
154             return p;
155         else
156         {
157             p=p->next;
158             ++(*i);
159         }
160     }
161     cout<<"当前链表中无此元素"<<endl;
162     exit(0);
163     return NULL;
164 }
165
166 //清空单循环链表
167 //保留表头结点,把链表中的
168 //其余所有结点全部释放。
169 void CList::Clear()
170 {
171     Node* p=NULL;
172     Node* q=NULL;
173     p=head->next;
174     while(p!=head)
175     {
176         q=p;
177         p=p->next;
178         delete q;
179     }
180     head->next = NULL;
181 }
182
183 //析构函数
184 //释放链表中的所有元素。
185 CList::~CList()
186 {
187     Node* p;
188     p=head;
189     while(p!=head)
190     {
191         p=p->next;
192         delete head;
193         head=p;
194     }
195 }

测试程序则放在main函数里:

 1 int main()
 2 {
 3     int i=0;
 4     Data e;
 5     int a[8]={2,4,6,8,5,1,7,9};
 6
 7     CList list;                    //创建链表类
 8     list.IsEmpty();                    //判断链表是否为空
 9     list.Create(a,8);                //将数据插入
10     list.Print();                    //显示
11     cout<<"链表长度:"<<list.Size()<<endl;
12
13     cout<<"输入要插入的元素和位置:";
14     cin>>e>>i;
15     list.Insert(e,i);                //插入数据
16     list.Print();
17     cout<<"当前链表长度为"<<list.Size()<<endl<<endl;
18
19     cout<<"输入要查找的元素值:";
20     cin>>e;
21     list.Locate(e,&i);                    //查找某元素
22     cout<<"这是第"<<i<<"个元素"<<endl<<endl;
23
24     list.IsEmpty();                    //判断链表是否为空
25
26     cout<<"输入要查找的元素位置:";
27     cin>>i;
28     e=list.GetElem(i);                    //查找第i个位置的元素
29     cout<<"这个元素值为:"<<e<<endl<<endl;
30
31     list.IsEmpty();                    //判断链表是否为空
32
33     cout<<"输入要删除的元素位置:";
34     cin>>i;
35     e=list.Delete(i);                    //删除第i个位置的元素
36     cout<<"这个元素值为:"<<e<<endl;
37     list.Print();
38     cout<<"当前链表长度为"<<list.Size()<<endl<<endl;
39
40     cout<<"输入要删除的元素位置:";
41     cin>>i;
42     e=list.Delete(i);                    //删除第i个位置的元素
43     cout<<"这个元素值为:"<<e<<endl;
44     list.Print();
45     cout<<"当前链表长度为"<<list.Size()<<endl<<endl;
46
47     list.Clear();
48     list.IsEmpty();                    //判断链表是否为空
49
50     return 0;
51 }

测试情况如下:

到此,线性表的几种基本实现已经结束了,下方可查看几种线性表的具体实现:

1.顺序存储:http://www.cnblogs.com/tenjl-exv/p/7469316.html

2.单链表:http://www.cnblogs.com/tenjl-exv/p/7470075.html

3.双向链表:http://www.cnblogs.com/tenjl-exv/p/7475518.html

这里说一下循环链表的优点:

① 从表中任意结点出发均可访问到表中其他结点,这使得某些操作在循环链表上容易实现。

② 插入删除操作中不需区分尾节点还是中间结点,以使操作简化

 

时间: 2024-08-06 10:58:34

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

数据结构第三篇——线性表的链式存储之单链表

线性表的链式存储结构的特点是用一组任意的存储单元来存储线性表的数据元素,这些单元可以分散在内存中的任意位置上,其在物理上可以是连续的,也可以是不连续的.具有链式存储结构的线性表称为线性链表. 为了表示出每个数据元素与其后继之间的关系,除了存储数据元素本身的信息之外,还需存储指示其直接后继的信息.这可以用一个结点(node)来完整的表示. 将节点中存储数据元素本身信息的域称为数据域:存储其直接后继位置的域称为指针域.指针域中存储的信息称作指针或链. 一般情况下,链表中每个结点可以包含若干个数据域和

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

?注:未经博主同意,不得转载. 前面讨论的单链表,每个结点中只有一个指针域,用来存放指向后继结点的指针,因此,从某个结点出发只能顺时针往后查找其他结点.若要查找某个结点的直接前驱,则需要从头指针开始沿链表探寻,处理起来十分不方便.为克服单链表的这一缺点,可引入双向链表. 双向链表中每一个结点含有两个指针域,一个指针指向其直接前驱结点,另一个指针指向直接后继结点.和单链表类似,双向链表一般也只有头指针唯一确定:同样也可设头结点,使得双向链表的某些操作简便一些. 双向链表结构定义如下:  双向链表是

数据结构开发(5):线性表的链式存储结构

0.目录 1.线性表的链式存储结构 2.单链表的具体实现 3.顺序表和单链表的对比分析 4.小结 1.线性表的链式存储结构 顺序存储结构线性表的最大问题是: 插入和删除需要移动大量的元素!如何解决? 链式存储的定义: 为了表示每个数据元素与其直接后继元素之间的逻辑关系:数据元素除了存储本身的信息外,还需要存储其直接后继的信息. 链式存储逻辑结构: 基于链式存储结构的线性表中,每个结点都包含数据域和指针域 数据域:存储数据元素本身 指针域:存储相邻结点的地址 专业术语的统一: 顺序表 基于顺序存储

《数据结构 - 线性表》链式存储 (单链表)

一:线性表定义 -<数据结构 - 线性表>顺序存储结构 二:为什么要 链式存储 线性表? - 因为在使用 顺序结构 存储方式存储的时候,每次进行 插入/删除 都需要大量移动元素的位置. - 所以设计出一种 存储空间不连续 的存储结构. - 这个线性表可能是这样的(存储位置不固定) -  三:链式存储 定义 -  因为链式存储,不是连续空间,所以需要两个信息 - 一个用于 存储数据元素,也叫做 数据域 - 一个用于 指向 下一个位置 的 指示信息,叫做指针域. - 指针域中存储的信息叫指针/链

数据结构之线性表(链式存储结构)

线性表的实现分顺序存储结构和链式存储结构 上一节我们主要介绍了顺序存储结构,在最后我们还分别总结了顺序存储结构的优缺点, 对于顺序结构的缺点,我们有没有什么好的解决方法呢? 我们今天要介绍的线性表的链式存储结构就可以很好的解决顺序结构的缺点,一起来看. 顺序结构最大的缺点就是在进行插入和删除操作的时候,如果插入位置不理想,那么我们需要移动大量的元素,那产生这一问题的原因是什么呢? 仔细分析后,我们可以发现在顺序存储结构中,他们相邻的元素的存储位置也是相邻的,我们在申请内存的的时候,是一次性申请一

【数据结构】-线性表的链式存储结构

引言:由于线性表的顺序存储结构在插入和删除时需要大量移动数据元素,从而引入线性表的链式存储结构. 线性表的链式存储结构:用一组任意的存储单元(可以连续也可以不连续)存储线性表的数据元素. 为了表示数据元素ai和其直接后继ai+1之间的逻辑关系,对ai来说,除了存储其本身的数据信息外,还需要存储其直接后继的存储位置.这两部分信息组成数据元素ai的存储映像(结点).它包含两个域:其中存储数据元素信息的域称为数据域:存储直接后继存储位置的域称为指针域. n个结点链接成一个链表,称为线性链表,由于此链表

数据结构--线性表的链式存储结构

一 线性表的链式存储结构 A.链式存储的定义为了表示每个数据元素与直接后继元素之间的逻辑关系:数据元素除了存储本身的信息外,还需要存储其直接后继的信息图示B链式存储逻辑结构基于链式存储结构的线性表中,每个结点都包含数据域和指针域1.数据域:存储数据元素本身2.指针域:存储相邻结点的地址图示C链表中的基本概念1.头结点--链表中的辅助结点,包含指向第一个数据元素的指针(方便插入和删除)2.数据结点--链表中代表数据元素的结点,表现形式为:(数据元素,地址)3.尾节点--链表中的最后一个数据结点,包

线性表的链式存储之单链表的尾插法

对单链表进行遍历.查找.插入.删除等操作,最终效果如下: 相关C代码如下: /*线性表的链式存储之单链表的尾插法*/ #include <stdio.h> #include <stdlib.h> #include <malloc.h> /*定义变量*/ typedef int DataType; typedef struct node{     //定义链表结点数据结构 DataType data; struct node * pNext; }NODE; typedef

线性表的链式存储

线性表的链式存储 线性表的链式存储 基本概念 设计与实现 实现代码 优缺点 1. 基本概念 链式存储定义 为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息外,还需要存储指示其直接后继的信息. 表头结点 链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息 数据结点 链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息 尾结点 链表中的最后一个数据结点,其下一元素指针为空,表示无后继. 2.设计与实现 在C语言中可以用结构体来定义链