线性表链式存储(双向循环链表)及其14种操作的实现

 

操作

时间复杂度(T(n))

空间复杂度(S(n))

判断是否为空

O(1)

O(1)

得到长度

O(n)

O(1)

转置链表

O(n)

O(1)

得到指定下标的元素

O(n)

O(1)

得到指定元素的下标

O(n)

O(1)

插入元素(只告诉插入到第几个结点之前,不告诉内存地址)

O(n)

搜索到指定下标的时间为O(n),更换指针指向的时间为O(1)

O(1)

需要开辟1个内存空间,即使插入1000个,也是O(1),因为需要的新内存空间是常数的,不是线性的

删除元素(只告诉删除第几个结点,不告诉地址)

O(n)

同上

O(1)

道理同插入元素

冒泡排序

O(n^2)

O(1)

道理同转置链表

将两个已经有序的链表(长度分别n,m)的合并到第一个链表,且保持新表有序

O(n+m)

虽然O(n+m)与O(n)同为线性阶,但是当m远大于n时,两者的差别会较大,写成O(n+m)更加准确

O(1)

不需要开辟新的内存空间,只需要改变指针的指向

/*   数据结构分析与学习专栏
*  Copyright (c) 2015, 山东大学计算机科学与技术专业学生
*  All rights reserved.
*   作    者:   高祥
*   完成日期:  2015 年 3 月 26 日
*   版 本 号:005
 
*任务描述:针对双向循环链表,实现15个基本操作
*    1:头插法建立双向循环链表;
*    2:尾插法建立双向循环链表;
*    3:输出双向循环链表的元素;
*    4:删除双向循环链表指定位置的节点;
*    5:向双向循环链表的指定位置插入节点;
*    6:查找双向循环链表指定下标的元素;
*     7:求出给定元素在双向循环链表中第一次出现的位置;
*    8:将双向循环链表的元素按照升序排序;
*    9:求双向循环链表的长度;
*    10:判断当前双向循环链表是否为空;
*    11:将双向循环链表反转;
*    12:求两个双向循环链表的并集到第三个双向循环链表并按照升序排列  ;
*    13:清空当前双向循环链表;
*    14:销毁双向循环链表  ;
 
*主要函数:
*   0:StatusInitList(LinkList &L);//每次建立链表之前首先分配链表头结点的内存
*   1:StatusInverseCreatList(LinkList L,int listsize);
   //头插法输入listsize个元素,建立起有头结点的双向循环链表L
*   2:StatusOrderCreatList(LinkList L,int listsize);
   //尾插法输入listsize个元素,建立起有头结点的双向循环链表L
*   3:StatusOutput(LinkList L);//输出双向循环链表
*   4:StatusListDelete(LinkList L,int index);//在带头结点的双向循环链表L中,删除第index个元素
*   5:StatusListInsert(LinkList L,int index,ElemType elem);
   //在带头结点的双向循环链表L中第index个位置之前插入元素elem
*   6:StatusGetElem(LinkList L,int index);
   //L为带头结点的双向循环链表的头指针,若第index个元素存在时,输出其值
*   7:StatusGetIndex(LinkList L,ElemType elem);
   //L为带头结点的双向循环链表的头指针,若元素elem存在时,输出该元素在链表中的第一次//出现的位置
*   8:StatusBubbleSort(LinkList L);//冒泡法排序
*   9:intListLength(LinkList L);//求出双向循环链表的长度
*  10:Status IsEmptyList(LinkList L);
   //当且仅当头结点和第一个结点均不为空时,双向循环链表才存在
*  11:Status ReverseList(LinkList L);//反转双向循环链表
*  12:void NonRecursiveMergeList(LinkList L1,LinkList L2);//非递归归并双向循环链表
*  13:void ClearList(LinkList L);//清空链表L的所有节点(头结点外)
*  14:Status DestroyList(LinkList &L);// 销毁单循环链表L
 
*注意:只有StatusInitList(LinkList &L)和Status DestroyList(LinkList &L)必须使用引用传参数
(对main函数中指针本身的修改),其余的函数没有必要将形参声明为引用。
*/
 
#include<iostream>
#include <cstdlib>
#include<algorithm>
using namespace std;
 
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
 
typedef int Status;//Status是函数的类型,其值是函数结果状态的代码
typedef int ElemType;//ElemType是数据元素的类型,使用时用户自行定义
 
typedef struct DuLNode
{
   ElemType data;
   struct DuLNode * next;
   struct DuLNode * prior;
} DuLNode,*DuLinkList;
 
DuLinkList L1=NULL,L2=NULL;
 
Status InitList(DuLinkList &L);//每次建立链表之前首先分配链表头结点的内存
 
Status InverseCreatList(DuLinkList L,intlistsize);//头插法输入listsize个元素,建立起有头结点的双向循环链表L
 
Status OrderCreatList(DuLinkList L,intlistsize);//尾插法输入listsize个元素,建立起有头结点的双向循环链表L
 
Status Output(DuLinkList L);//输出双向循环链表
 
Status ListDelete(DuLinkList L,intindex);//在带头结点的双向循环链表L中,删除第index个元素
 
Status ListInsert(DuLinkList L,intindex,ElemType elem);//在带头结点的双向循环链表L中第index个位置之前插入元素elem
 
Status GetElem(DuLinkList L,int index);//L为带头结点的双向循环链表的头指针,若第index个元素存在时,输出其值
 
Status GetIndex(DuLinkList L,ElemTypeelem);//L为带头结点的双向循环链表的头指针,若元素elem存在时,输出该元素在链表中的第一次出现的位置
 
Status BubbleSort(DuLinkList L);//冒泡法排序
 
int ListLength(DuLinkList L);//求出双向循环链表的长度
 
Status IsEmptyList(DuLinkList L);//当且仅当头结点和第一个结点均不为空时,双向循环链表才存在
 
Status ReverseList(DuLinkList L);//反转双向循环链表
 
void NonRecursiveMergeList(DuLinkListL1,DuLinkList L2);//非递归归并双向循环链表
 
void ClearList(DuLinkList L);//清空链表L的所有节点(头结点外)
 
Status DestroyList(DuLinkList &L);// 销毁双向循环链表L
 
void Interaction();//输出操作
 
int main()
{
   Interaction();
 
   int operate;
   int listsize;
 
   while(cin>>operate)
    {
       switch (operate)
       {
       case 0:
           goto END;
 
       case 1:
           if(InitList(L1))
           {
                cout<<"请输入链表的大小:";
                int listsize;
                cin>>listsize;
                InverseCreatList(L1,listsize);
           }
           break;
 
       case 2:
           if(InitList(L1))
           {
                cout<<"请输入链表的大小:";
                cin>>listsize;
                InitList(L1);
                OrderCreatList(L1,listsize);
           }
           break;
 
       case 3:
           Output(L1);
           break;
 
       case 4:
           cout<<"请输入要删除元素的位置:";
           int index;
           cin>>index;
           ListDelete(L1,index);
           break;
 
       case 5:
           cout<<"请输入要插入的位置和元素的大小:";
           ElemType elem;
           cin>>index>>elem;
           ListInsert(L1,index,elem);
           break;
 
       case 6:
           cout<<"请输入要查找的元素的位置:";
           cin>>index;
           GetElem(L1,index);
           break;
 
       case 7:
           cout<<"请输入要查找的元素:";
           cin>>elem;
           GetIndex(L1,elem);
           break;
 
       case 8:
           BubbleSort(L1);
           break;
 
       case 9:
           cout<<"双向循环链表的长度是:"<<ListLength(L1)<<endl;
           break;
 
       case 10:
           if(!IsEmptyList(L1))
           {
                cout<<"当前双向循环链表不为空。\n";
           }
           else
           {
                cout<<"当前双向循环链表为空。\n";
           }
           break;
 
       case 11:
           ReverseList(L1);
           break;
 
       case 12:
           if(!IsEmptyList(L1))
           {
                InitList(L2);
                cout<<"请输入元素的个数(尾插法建立链表):";
                cin>>listsize;
                OrderCreatList(L2,listsize);
 
                BubbleSort(L1);
                BubbleSort(L2);
 
                NonRecursiveMergeList(L1,L2);
                cout<<"归并后的链表是:";
                Output(L1);
 
                free(L2);
                L2=NULL;
           }
           else
           {
                cout<<"请先建立第一个链表。\n";
           }
           break;
 
       case 13:
           ClearList(L1);
           break;
 
       case 14:
           DestroyList(L1);
           cout<<"释放内存完毕,销毁双向循环链表成功。进行其他操作请先创建双向循环链表。\n";
           break;
 
       default:
           cout<<"请输入正确的操作编号!\n";
           break;
       }
    }
 
END://释放两个指针的内存
   DestroyList(L1);
   DestroyList(L2);
   return 0;
}
 
Status InitList(DuLinkList &L)//每次建立链表之前首先分配链表头结点的内存
{
   L=(DuLinkList)malloc(sizeof(DuLNode));
   if(L)
    {
       cout<<"分配内存成功。已建立空双向循环链表。\n";
       L->prior=L;//头结点的两个指针均指向自身
       L->next=L;
       return OK;
    }
   cout<<"分配内存失败,已退出!\n";
   return FALSE;
}
 
Status InverseCreatList(DuLinkList L,intlistsize)
//头插法输入listsize个元素,建立起有头结点的双向循环链表L
//头插法特点:建立的链表元素顺序与输入的顺序相反,每次插入元素都插在头部,较好理解
{
   cout<<"请输入元素:";
   for(int i=1; i<=listsize; i++)
    {
       DuLinkList p=(DuLinkList)malloc(sizeof(DuLNode));
       cin>>p->data;
       p->next=L->next;
       p->prior=L;
 
       if(L->next!=L)
       {
           L->next->prior=p;//已经存在结点
       }
       else
       {
           L->prior=p;
//当目前链表中没有结点时,将头结点的指针指向将要插入的第一个节点,此后,尾结点(头结点的前驱)不再改变
       }
 
       L->next=p;//完成插入节点
    }
 
   cout<<"新链表是:";
   Output(L);
   return OK;
}
 
Status OrderCreatList(DuLinkList L,intlistsize)
//尾插法输入listsize个元素,建立起有头结点的双向循环链表L
//尾插法特点:建立的链表元素顺序与输入的顺序相同,每次插入元素都插在尾部,细节注释如下
{
   DuLinkList r=L;//必须增加一个尾指针r,使其始终指向当前链表的尾结点
   cout<<"请输入元素:";
   for(int i=1; i<=listsize; i++)
    {
       DuLinkList p=(DuLinkList)malloc(sizeof(DuLNode));
       cin>>p->data;
       p->prior=r;
        p->next=r->next;
       r->next=p;
       r=p;//更新尾指针
       L->prior=r;//形成双向循环链表
       r->next=L;
    }
 
   cout<<"新链表是:";
   Output(L);
   return OK;
}
 
Status Output(DuLinkList L)//输出双向循环链表
{
   if(!IsEmptyList(L))//增强程序的鲁棒性
    {
       DuLinkList p=L->next;
       while(p!=L)//终结循环的条件是当前结点≠头结点
       {
           cout<<p->data<<" ";
           p=p->next;
       }
       cout<<"\n";
    }
   else
    {
       cout<<"链表为空,无法输出。\n";
       return ERROR;
    }
}
 
Status ListDelete(DuLinkList L,int index)
//在带头结点的双向循环链表L中,删除第index个元素
{
   if(index<1||index>ListLength(L))
    {
       cout<<"位置越界,操作失败,已退出。\n";
       return ERROR;
    }
 
   int j=0;//计数器
   DuLinkList p=L;//使之为头结点,而不是第一个节点,若p=L->next,会导致无法删除第一个节点
   while(j<=index-2)//当j==index-1,即p为删除位置的前一个结点时退出循环
    {
       if(p)
       {
           p=p->next;
           j++;
       }
       else
       {
           cout<<"位置越界,操作失败,已退出。\n";
           return ERROR;
       }
    }
   DuLinkList q=p->next;//被删除的结点
   cout<<"被删除的元素是:"<<q->data<<"\n";
 
   p->next=q->next;//修改两个指针
   q->next->prior=q->prior;
 
   free(q);//释放对应节点的内存
   q=NULL;//置空指针,否则q会成为迷途指针,引发错误
   cout<<"新链表是:";
   Output(L);
   return OK;
}
 
Status ListInsert(DuLinkList L,intindex,ElemType elem)
//在带头结点的双向循环链表L中第index个位置之前插入元素elem
{
   if(index<1||index>ListLength(L))
    {
       cout<<"插入位置越界,操作失败,已退出。\n";
       return ERROR;
    }
 
   int j=0;
   DuLinkList p=L;//原理同删除元素
   while(j<=index-2)
    {
       if(p)
       {
           p=p->next;
           j++;
       }
       else
       {
           cout<<"插入位置越界,操作失败,已退出。\n";
           return FALSE;
       }
    }
 
   DuLinkList newnode=(DuLinkList)malloc(sizeof(DuLNode));
   newnode->data=elem;
 
    newnode->next=p->next;//修改四个指针
   newnode->prior=p;
   p->next->prior=newnode;
   p->next=newnode;
 
   cout<<"插入元素成功。新链表是:";
   Output(L);
   return OK;
}
 
Status GetElem(DuLinkList L,int index)
//L为带头结点的双向循环链表的头指针,若第index个元素存在时,输出其值
{
   if(index<1||index>ListLength(L))
    {
       cout<<"位置越界,操作错误,已退出。\n";
       return FALSE;
    }
 
   DuLinkList p=L;//初始化:p指向头结点
   int j=0; //计数器
   while(p&&j<index)//顺指针向后查找
    {
       p=p->next;
       j++;
    }
   cout<<"已找到,位置为"<<index<<"处的元素是:"<<p->data<<"。\n";
   return OK;
}
 
Status GetIndex(DuLinkList L,ElemType elem)
//L为带头结点的双向循环链表的头指针,若元素elem存在时,输出该元素在链表中的第一次出现的位置
{
   if(!IsEmptyList(L))
    {
       int j=1;
       DuLinkList p=L->next;
       while(p!=L)
       {
           if(p->data==elem)
           {
                cout<<"元素"<<elem<<"是双向循环链表中的第"<<j<<"个元素。\n";
                return OK;
           }
           j++;
           p=p->next;
       }
       cout<<"元素"<<elem<<"不在双向循环链表中。\n";
       return FALSE;
    }
   else
    {
       cout<<"双向循环链表为空,无法查找,已退出。\n";
       return FALSE;
    }
}
 
Status BubbleSort(DuLinkList L)//冒泡法排序
{
   if(!IsEmptyList(L))
    {
       DuLinkList p=L->next;
       while(p!=L)
       {
           DuLinkList q=p->next;
           while(q!=L)
           {
                if(q->data<p->data)
                {
                   swap(q->data,p->data);
                }
                q=q->next;
           }
           p=p->next;
       }
 
       cout<<"排序后的链表是:";
       Output(L);
       return OK;
    }
   cout<<"链表为空,操作错误!已退出!\n";
}
 
int ListLength(DuLinkList L)//求出双向循环链表的长度
{
   int cnt=0;
   DuLinkList p=L;
   if(p)
    {
       p=p->next;
    }
   while(p!=L)
    {
       cnt++;
       p=p->next;
    }
   return cnt;
}
 
Status IsEmptyList(DuLinkList L)//当且仅当头结点和第一个结点均不为空时,双向循环链表才存在
{
   if(L!=NULL&&L->next!=L&&L->prior!=L)//必须先检验L是否为NULL,若L==NULL,不事先检查的话,会RuntimeError
    {
       return FALSE;
    }
   return TRUE;
}
 
Status ReverseList(DuLinkList L)//反转双向循环链表
{
   if(!IsEmptyList(L))
    {
       DuLinkList p=L->next;
       while(p!=L)
       {
           DuLinkList q=p->next;//一定先将将要交换自身指针的结点的下一个结点预存起来,否则易出错
           swap(p->next,p->prior);//交换自身结点
           p=q;//更新未交换的结点
       }
       swap(L->next,L->prior);//交换头结点的指针
 
       cout<<"转置后的链表为:";
       Output(L);
       return OK;
    }
   cout<<"链表为空,无法转置,已退出。\n";
   return FALSE;
}
 
 
void NonRecursiveMergeList(DuLinkListL1,DuLinkList L2)//非递归归并双向循环链表
//递归归并双向循环链表十分繁琐,此处不再列出
{
    DuLinkListp1,p2,p3,q,end1,end2;
   p1=L1->next;//第一条链表指针
   p2=L2->next;//第一条链表指针
   end1=L1->prior;//将链表的尾结点指针预存起来,便于后续操作
   end2=L2->prior;
   p3=L1;//归并后链表的头指针,使之为L1的头指针,即将L1变为归并后的链表
 
   while(p1!=L1&&p2!=L2)//当某一条链表归并完成后退出
    {
       if(p1->data<=p2->data)
       {
           q=p1->next;//预存下一个将要归并的节点指针
           p1->next=L1;//修改四个指针
           p3->next=p1;
           p1->prior=p3;
           L1->prior=p1;
           p3=p1;//更新指针
           p1=q;
       }
       else
       {
           q=p2->next;//同上
           p2->next=L1;
           p3->next=p2;
           p2->prior=p3;
           L1->prior=p2;
           p3=p2;
           p2=q;
       }
    }
 
   if(p1!=L1)//L1链表未归并完成,L2链表已经归并完成,只需要修改3个指针
    {
       p3->next=p1;
       p1->prior=p3;
       L1->prior=end1;//形成循环
    }
 
   if(p2!=L2)//L1链表归并完成,L2链表未归并完成,需要修改4个指针
    {
       p3->next=p2;
       p2->prior=p3;
       L1->prior=end2;
       end2->next=L1;
    }
 
   cout<<"归并后的双向循环链表是:";
   Output(L1);
}
 
void ClearList(DuLinkList L)//清空链表L的所有节点(头结点外)
{
   if(!IsEmptyList(L))
    {
       DuLinkList p=L->next;
       DestroyList(p);//销毁(释放)头结点后所有结点的内存
       L->next=L;//置空
       L->prior=L;
       cout<<"清空双向循环链表成功。\n";
    }
   else
    {
       cout<<"链表本身为空,无需清空!\n";
    }
}
 
Status DestroyList(DuLinkList &L)// 销毁双向循环链表L
{
   if(!IsEmptyList(L))//必须先检验,防止L==NULL
    {
       DuLinkList p=L->next;
       free(L);//释放指针所指向的内存后,指针本身并不改变
       while(p!=L)
       {
           DuLinkList q=p->next;
           free(p);
           p=q;
       }
    }
   L=NULL;
   return OK;
}
 
void Interaction()//输出操作
{
   cout<<"请输入对应操作的序号:\n";
   cout<<"0:退出程序;\n";
   cout<<"1:头插法建立双向循环链表;\n";
   cout<<"2:尾插法建立双向循环链表;\n";
   cout<<"3:输出双向循环链表的元素;\n";
   cout<<"4:删除双向循环链表指定位置的节点;\n";
   cout<<"5:向双向循环链表的指定位置插入节点;\n";
   cout<<"6:查找双向循环链表指定下标的元素;\n";
   cout<<"7:求出给定元素在双向循环链表中第一次出现的位置;\n";
   cout<<"8:将双向循环链表的元素按照升序排序;\n";
   cout<<"9:求双向循环链表的长度;\n";
   cout<<"10:判断当前双向循环链表是否为空;\n";
   cout<<"11:将双向循环链表反转;\n";
   cout<<"12:求两个双向循环链表的并集到第三个双向循环链表并按照升序排列;\n";
   cout<<"13:清空当前双向循环链表;\n";
   cout<<"14:销毁双向循环链表  ;\n";
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值