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