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

来源:互联网 发布:c并发编程实战 pdf 编辑:程序博客网 时间:2024/06/16 21:27

 

操作

时间复杂度(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