线性表链式存储(双向循环链表)及其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
- 线性表链式存储(双向循环链表)及其14种操作的实现
- 线性表链式存储及其实现(单链表,循环链表,双向链表)
- 线性表链式存储结构实现 --双向循环链表
- 线性表链式存储(单循环链表)及其15种操作的实现
- 线性表链式存储(静态链表)及其12种操作的实现
- 线性表链式存储(单链表)及其15种操作的实现
- 数据结构与算法——线性表链式存储(双向循环链表)
- 线性表链式存储结构实现 --单向循环链表
- 线性表链式存储实现各种操作
- 线性表链式存储的实现
- 线性表链式存储的实现
- 线性表链式存储的实现详解
- 线性表链式存储的实现详解
- 线性表链式存储结构实现--静态链表
- 线性表链式存储实现
- 双向链表链表的实现
- 线性表链式存储结构下基本操作的实现(初始化、赋值、取值、插入、删除、归并等)
- 线性表链式存储结构基本操作
- BestCoder Round #33(zhx's contest-快速乘法)
- [Python学习] 简单网络爬虫抓取博客文章及思想介绍
- [Python学习] 专题四.文件基础知识
- Android的Intent
- nginx下discuz x3的伪静态规则
- 线性表链式存储(双向循环链表)及其14种操作的实现
- python2.7.6安装web.py 0.37报编码错误
- [python学习] 简单爬取维基百科程序语言消息盒
- iOS 推送通知”详解:从创建到设置到运行
- Reorder List
- twemproxy简介
- iOS本地通知:UILocalNotification
- [python学习] 简单爬取图片网站图库中图片
- 【分析】config-portable文件