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

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

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

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

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

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

单循环链表定义如下:

 

 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

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

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

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

 

posted @ 2017-09-21 18:43  T丶jl  阅读(648)  评论(0编辑  收藏  举报