操作 |
时间复杂度(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"; }