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

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

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

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

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

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

    单循环链表定义如下:

     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

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

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

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

     

  • 相关阅读:
    hihoCoder #1176 : 欧拉路·一 (简单)
    228 Summary Ranges 汇总区间
    227 Basic Calculator II 基本计算器II
    226 Invert Binary Tree 翻转二叉树
    225 Implement Stack using Queues 队列实现栈
    224 Basic Calculator 基本计算器
    223 Rectangle Area 矩形面积
    222 Count Complete Tree Nodes 完全二叉树的节点个数
    221 Maximal Square 最大正方形
    220 Contains Duplicate III 存在重复 III
  • 原文地址:https://www.cnblogs.com/tenjl-exv/p/7476246.html
Copyright © 2011-2022 走看看