几种典型线性表的链式存储结构的比较
两种存储结构比较线性表

n!=
五、栈的应用
2、计算表达式
(1)由计算规则得算符优先关系表
3+5*3 θ 1:先来的算符 3+5+5 θ 2:后来的算符 * < < > < ) > > > =
θ1 θ2
+ \ (
+ > > > <
> > > <
(2)原理
两工作栈:一个算符栈,一个操作数栈
a.读取到操作数,直接入操作数栈 b.读取到运算符,取运算符栈栈顶元素与该算符比 较优先级: “<”:读取符号入运算符栈;
初始:front=rear=0
队空:front=rear
max-1
…
队满:rear=max
1
0
四、队列的顺序存储结构
假溢出的问题:用循环队列来解决
下一个rear计算公式:rear=(rear+1)mod max
循环队列队空队满标志冲突的问题: 以牺牲一个存储空间为代价,当判断到(下一个 rear==front)时,即认为队满。 实际上,max个空间只存放了(max-1)个元素
结束
四、栈的链式存储结构
data link
设指针域指向次顶结点
规定:top指向栈顶元素地址
基本操作:
判断空栈 进栈
出栈 利用链式存储结构存储栈,可
解决栈的致命错误——上溢
五、栈的应用
1、递归调用
一个子程序调用自身,称为递归调用。
例:阶乘的计算 1 (n=0,1) n*(n-1)! (n>1)
第三章 栈与队列
两种重要的,限定操作的线性结构。
第3章线性表的链式存储

(a) 空循环链表
L
a1
a2
...
an
(b) 非空循环链表
3.1.3 双向链表
在单链表结点中只有一个指向其后继结点的next 指针域,而找其前驱则只能从该链表的头指针开始,顺 着各结点的next指针域进行查找,也就是说找后继的时 间复杂度是O(1),找前驱的时间复杂度是O(n)。如果也 希望找前驱像后继那样快,则只能付出空间的代价:每 个结点再加一个指向前驱的指针域prior,结点的结构修 改为下图,这样链表中有两个方向不同的链,用这种结 点组成的链表称为双向链表。
1.带头结点的单链表 2.不带头结点的单链表
3.3.3 单链表插入操作的实现
单链表的插入操作是指在表的第i个位置结点处插入 一个值为data的新结点。插入操作需要从单链表的第一个结 点开始遍历,直到找到第i个位置的结点。插入操作分为在 结点之前插入的前插操作和在结点之后插入的后插操作。
1.前插操作 2.后插操作
2.整数型单链表算法
3.不带头结点的单链表算法
3.2.2 尾插法单链表的创建实现
用头插法实现单链表的创建,比较简单,但读入的 数据元素的顺序与生成的链表中元素的顺序是相反的。若希 望两者次序一致,则用尾插法创建单链表。为了快速找到新 结点插入到链表的尾部位置,所以需加入一个尾指针r用来 始终指向链表中的尾结点。初始状态:头指针L和尾指针r均 为空,把各数据元素按顺序依次读入,申请结点,将新结点 插入到r所指结点的后面,然后r指向新结点,直到读入结束 标志为止。
3.2.2 尾插法单链表的创建实现
L
插入P前的尾指针 插入P后的尾指针
r
3
4
P1
x^
2
3.3 单链表运算的实现
比较顺序存储结构和链式存储结构

1、试比较挨次存储结构和链式存储结构的优缺点。
在什么状况下用挨次表比链表好?答:①挨次存储时,相邻数据元素的存放地址也相邻;内存中可用存储单元的地址必需是连续的。
优点:存储密度大( = 1),存储空间采用率高。
缺点:插入或删除元素时不便利。
②链式存储时,相邻数据元素可随便存放,但所占存储空间分两部分,一部分存放结点值,另一部分存放表示结点间关系的指针. 优点:插入或删除元素时很便利,使用敏捷。
缺点:存储密度小(G),存储空间采用率低。
挨次表相宜于做查找这样的静态操作;链表宜于做插入,删除这样的动态操作。
若线性表的长度变化不大,且其主要操作是查找,则采纳挨次表;若线性表的长度变化较大,且其主要操作是插入、删除操作,则采纳链表。
顺序表和链表的比较:挨次表与链表的比较基于空间的比较•存储安排方式:挨次表的存储空间是静态安排的;链表的存储空间是动态安排的存储密度=结点数据本身所占的存储量/结点结构所占的存储总量:挨次表的存储密度=1;链表的存储密度V1基于时间的比较存取方式:挨次表可以随机存取,也可以挨次存取;链表是挨次存取的;插入/删除时移动元素个数; 挨次表平均需要移动近一半元素;链表不需要移动元素,只需要修改指针挨次表和链表的比较挨次表和链表各有短长。
在实际应用中毕竟选用哪一种存储结构呢?这要依据详细问题的要求和性质来打算。
储易于事先确定其大小时,为了节省 密 存储空间,宜采纳挨次表作为存储 度结构。
基I 存I 随机存取结构,对表中任一结点都I 挨次存取结构,链表中的结点,需II 于I 取I 可在O(I)时间内直接取得 I 从头指针起顺着链扫描才能取得。
I方 线性表的操作主要是进行查找,很 法少做插入和删除操作时,采纳挨次I 表做存储结构为宜。
在链表中的任何位置上进行插入和 删除,都只需要修改指针。
对于频 繁进行插入和删除的线性表,宜采 用链表做存储结构。
若表的插入和删除主要发生在表的首尾两端,则 采纳尾指针表示的I通常有以下几方面的考虑:! I 存I 为1。
线性表的链式存储

if(j<i && temp->next = =L) /*无合适的插入位置,*/ return FALSE;
node=( LinkList *)malloc(sizeof(LinkList)); if(node==NULL) /*申请结点不成功*/ return FALSE; node->next=temp->next;
数据结构
线性表的链式存储
为了提高增加、删除元素的效率,介绍线性表 的另一种存储方式——链式存储。在链式存储方 式中,能够方便地增加和删除线性表中的元素, 但是同时也使随机存取、获取直接前趋和直接后 继变得较为复杂。
链表:以链式结构存储的线性表称之为
链表(Linked List)。链式存储结构
是用一组任意的存储单元来存储线性表 的结点。也就是说,链式存储结构中, 存储单元可以是相邻的,也可以是不相 邻的;同时,相邻的存储单元中的数据, 不一定是相邻的结点。
DL=(DNode *)malloc(sizeof(DNode));
if(DL= =NULL) return FALSE;/*申请失败*/
DL->prior=DL->next=NULL;
return TRUE;
}
本算法时间复杂度为O(1)。
双向链表的操作
双向链表为空表的判断 从图中可以看出,双向链表是否为空表,要看
return TRUE;
return FALSE;
}
node->next=temp->next;
else/*插入位置不合理*/ temp->next=node;
return FALSE;} return TRUE; }
线性表的链式存储结构

19
1. 初始化链表 :即只有一个头结点,并且头结点的 初始化链表CL:即只有一个头结点, next域指向它自身。 域指向它自身。 域指向它自身 int InitList(LinkList *CL) { CL->head=(*LNode)malloc(sizeof(LNode)); if (CL->head) {CL->head->next=CL->head; return OK;} //让next域指向它自身 让 域指向它自身 else return ERROR ; }
16
10. 在链表 中第 个数据元素之前插入数据元素 在链表L中第 个数据元素之前插入数据元素e 中第i个数据元素之前插入数据元素 int ListInsert(LinkList *L,int i,EntryType e) { LNode *p,*s; int j; if (i<1||i>ListLength(L)+1) return ERROR; s=(LNode*)malloc(sizeof(LNode));//s为存放 的结点 为存放e的结点 为存放 if (s==NULL) return ERROR; s->data=e; for (p=L->head,j=0;p&&j<i-1;p=p->next;j++); //寻找第 个结点 寻找第i-1个结点 寻找第 s->next=p->next; p->next=s; //将s结点插入 将 结点插入 return OK; }//P25图2-9。 图 。
8
2. 销毁链表 :删除链表中包括头结点在内所有结点。 销毁链表L:删除链表中包括头结点在内所有结点。 void DestoryList(LinkList *L) { LNode *p; while (L->head){ //依次删除链表中的所有结点 依次删除链表中的所有结点 依次
数据结构—线性表的两种存储结构的比较

在两种存储结构下实现线性表的创建,插入,删除,按值查找一、使用线性表的链式存储结构实现#include <stdio.h>#include <stdlib.h>typedef struct LNode{int data; //链表数据struct LNode* next; //链表指针}LNode,*LinkList;/*头插法-建立单链表*/LinkList HeadCreate(LinkList la){int num;la=(LinkList)malloc(sizeof(LNode)); //建立头结点la->next=NULL;scanf("%d",&num);while(num!=10){LNode *p=(LinkList)malloc(sizeof(LNode));p->data=num;p->next=la->next;la->next=p;scanf("%d",&num);}return la;}/*尾插法-建立单链表*/LinkList TailCreate(LinkList la){int num;la=(LinkList)malloc(sizeof(LNode));la->next=NULL;LinkList s,r=la;scanf("%d",&num);while(num!=10){s=(LinkList)malloc(sizeof(LNode));s->data=num;r->next=s;r=s;scanf("%d",num);}r->next=NULL;return la;}/*单链表遍历*/void TravelList(LinkList la){LinkList p=la->next;while(p!=NULL){printf("%d->",p->data);p=p->next;}printf("\n");}/*单链表的按位查找*/LinkList GetElem(LinkList la,int i){int j=1;LNode* p=la->next;if(i<1)return NULL;while(p && j<i){p=p->next;j++;}return p;}/*单链表的按值查找*/LinkList LocalElem(LinkList la,int e) {LNode* p=la->next;while(p!=NULL && p->data!=e)p=p->next;return p;}/*单链表插入操作*/bool InsertList(LinkList la,int i,int e){//在la链表中的i位置插入数值eint j=1;LinkList p=la,s;while(p && j<i){p=p->next;j++;}if(p==NULL)return false;if((s=(LinkList)malloc(sizeof(LNode)))==NULL)return false;s->data=e;s->next=p->next;p->next=s;return true;}/*单链表删除操作*/bool DeleteList(LinkList la,int i){int j=1;LinkList p=la,q;while(p && j<i) //p指向第i-1个元素{p=p->next;j++;}if(p==NULL || p->next==NULL) //表示不存在第i-1个和第i的元素return false;q=p->next;p->next=q->next;free(q);return true;}/*单链表的表长*/int LengthList(LinkList la)int nLen=0;LinkList p=la->next;while(p){p=p->next;nLen++;}return nLen;}/*单链表逆置*/LinkList Reserve(LinkList la){if(la==NULL || la->next==NULL)return la;LinkList p=la->next,q=p->next,r=q->next;la->next=NULL;p->next=NULL;while(r!=NULL){q->next=p;p=q;q=r;r=r->next;}q->next=p;la->next=q;return la;}int main(){LNode la;LinkList p;p=HeadCreate(&la); //头插法创建单链表TravelList(p);printf("%p\n",GetElem(p,1)); //获得第1个结点地址InsertList(p,2,10); //在链表的第2个位置插入元素10TravelList(p);DeleteList(p,3); //删除链表的第3个元素TravelList(p);printf("%d\n",LengthList(p)); //获得链表长度p=Reserve(p);TravelList(p);return 0;}//运行结果//5 6 12 7 8 14 9 3 2 5 14 10头插法创建链表//14->5->2->3->9->14->8->7->12->6->5-> 显示链表//00382490第一个结点的地址//14->10->5->2->3->9->14->8->7->12->6->5-> 插入元素值为10的结点//14->10->2->3->9->14->8->7->12->6->5-> 删除第三个结点//11 获//5->6->12->7->8->14->9->3->2->10->14-> 链表逆置//Press any key to continue二、使用线性表的顺序存储结构实现#include<stdio.h>#define MaxSize 50struct SqList{int data[MaxSize]; //存放顺序表的元素int length; //存放顺序表的长度};/*顺序表的插入操作*/bool InsertList(SqList&L,int i,int e){//在顺序表中第i个位置插入数值eint j;if(i<1 || i>L.length)return false;if(L.length>MaxSize)return false;for(j=L.length;j>=i;j--) //将第i个起得数据后移L.data[j]=L.data[j-1];L.data[j]=e;L.length++;return true;}/*顺序表的删除*/bool DeleteList(SqList&L,int i){//删除顺序表中第i个元素int j;if(i<1 || i>L.length)return false;for(j=i;j<L.length;j++)L.data[j-1]=L.data[j];L.length--;return true;}/*顺序表的按值查找*/int LocateElem(SqList&L,int e){for(int i=0;i<L.length;i++)if(L.data[i]==e)return i+1;return 0;}/*顺序表的输出*/void OutPutList(SqList&L){for(int i=0;i<L.length;i++)printf("%d ",L.data[i]);printf("\n");}int main(){SqList list;int A[5]={1,4,7,2,10};/*初始化顺序表*/for(int i=0;i<5;i++)list.data[i]=A[i];list.length=5;OutPutList(list);InsertList(list,3,12);OutPutList(list);DeleteList(list,3);OutPutList(list);printf("%d\n",LocateElem(list,10));return 0;}//运行结果//1 4 7 2 10 创建并输出顺序表//1 4 12 7 2 10 在3的位置插入值为12的元素//1 4 7 2 10 删除第三个元素//5 输出值为10的元素的位置//Press any key to continue上面是我用两种存储方式实现线性表的创建、插入、删除和按值查找的功能,还包含一些额外的功能,你可以自己根据我的代码改进,让代码更符合你的要求。
数据结构-线性表链式存储结构

04 线性表链式存储结构的实 现
C语言实现
创建链表
通过动态内存分配,创建链表节 点并逐个连接起来,形成链表。
插入节点
在链表指定位置插入节点,需要 更新插入位置节点的指针域,使 其指向新插入的节点。
删除节点
删除链表中的指定节点,需要更新被 删除节点前一个节点的指针域,使其 指向被删除节点的下一个节点。
01
遍历链表
从头节点开始,依次访问链表中的每 个节点,输出节点的数据值。
05
03
插入节点
在链表指定位置插入节点,需要更新 插入位置节点的引用,使其指向新插 入的节点。
04
删除节点
删除链表中的指定节点,需要更新被 删除节点前一个节点的引用,使其指 向被删除节点的下一个节点。
Python语言实现
在Python中,可以使
THANKS FOR WATCHING
感谢您的观看
适用场景
链式存储结构适用于需要频繁进行插入、删除等操作的数据结构,如动态数组、队列、链表等。
展望
01 02 03
未来发展方向
随着大数据和云计算的普及,数据结构的应用场景越来越 广泛,链式存储结构作为其中的一种重要形式,未来将有 更多的应用场景和优化空间。例如,针对大数据场景下的 链式存储结构优化、新型的链式数据结构等都是值得研究 的方向。
06 总结与展望
总结
定义与特点
链式存储结构是线性表的另一种存储方式,它通过在数据元素之间建立指针链接,实现了数据元素的逻辑顺序与物理 顺序的分离。相比于顺序存储结构,链式存储结构具有更好的动态性,能够方便地插入、删除等操作。
基本操作
链式存储结构支持的主要操作包括插入、删除、查找等,这些操作的时间复杂度通常为O(1)、O(n)、O(n),其中n为链表 长度。
数据结构(二):线性表的链式存储结构

数据结构(⼆):线性表的链式存储结构1、为什么要使⽤链式存储结构?因为我们前⾯讲的线性表的顺序存储结构,他是有缺点的。
最⼤的缺点就是插⼊和删除时需要移动⼤量元素,这显然就需要耗费时间。
要解决这个问题,我们就需要分析⼀下为什么当插⼊和删除时,就要移动⼤量元素,因为相邻两元素的存储位置也具有相邻关系,它们在内存中的位置也是挨着的,中间没有空隙,当然就⽆法快速介⼊,⽽删除之后。
当中就会留出空隙,⾃然就需要弥补。
问题就出在这⾥。
为了解决这个问题,⾃然⽽然的就出现了链式存储结构。
2、线性表链式存储结构的特点:线性表的链式存储结构不考虑元素的存储位置,⽽是⽤⼀组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的,这就意味着,这些数据元素可以存在内存未被占⽤的任意位置。
顺序存储结构:只需要存储数据元素信息。
链式存储结构:除了要存储数据元素信息之外,还要存储⼀个指⽰其直接后继元素的存储地址。
3、关键词:数据域:存储数据元素信息的域。
指针域:存储直接后继位置的域。
指针或链:指针域中存储的信息。
结点(Node):指针域+数据域组成数据元素的存储映像。
头指针:链表中第⼀个结点的存储位置。
头节点:在单链表的第⼀个结点前附设⼀个结点,成为头结点。
头结点的数据域不可以存储任何信息,可以存储线性表的长度等附加信息,头结点的指针域存储指向第⼀个结点的指针。
4、单链表:定义:n个结点链成⼀个链表,即为线性表的链式存储结构,因此此链表的每个结点中只包含⼀个指针域,所以叫做单链表。
PS:线性链表的最后⼀个结点指针为“空”,通常⽤NILL或“^”符号表⽰。
头节点:在单链表的第⼀个结点前附设⼀个结点,成为头结点。
头结点的数据域不可以存储任何信息,可以存储线性表的长度等附加信息,头结点的指针域存储指向第⼀个结点的指针。
5、头结点与头指针的异同(1)头结点头结点是为了操作的统⼀和⽅便⽽设⽴的,放在第⼀个元素的结点之前,其数据域⼀般⽆意义(也可存放链表的长度)有了头结点,对第⼀元素结点前插⼊和删除第⼀结点,其操作就统⼀了头结点不⼀定是链表的必要素(2)头指针头指针式指向第⼀个结点的指针,若链表有头结点,则是指向头结点的指针。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
delete head;
}
Company Logo
总结
1.访问方式: 单链表:如果访问任意结点每次只能从头开始顺序向后访问 单循环链表:可以从任何一个结点开始,顺序向后访问到达 任意结点 双向链表:可以从任何结点开始任意向前向后双向访问 2.操作: 单链表和单循环链表:插入删除第i个结点需要移动到第i-1 个结点 双链表:可以在当前结点前面或者后面插入,可以删除前趋 和后继(包括结点自己) 3.存储: 单链表和单循环链表存储密度大于双链表
while(p->next!=head&&i<position) { p=p->next; i++; } node* newn=new node; newn->data=data; newn->next=p->next; p->next=newn; length++; return true; }
/moban
双向链表的构造函数
Dlist(){ head=new dnode; tail=new dnode; head->next=tail; tail->prior=head; tail->next=NULL; head->prior=NULL; length=0; }
双向链表与单链表的对比
2.从插入和删除算法上来 说,双向链表需要同时修 改两个方向上的指针,当 然,两种表对于这两个算 法的时间复杂度都是O(n ) 3.无论是单链表还是双 向链表,在析构的时候 所用到的方法可以是一 样的。也就是说都可以 从第一个结点开始进行 内存的释放。
/moban
Thank You !
循环链表与单链表的对比
1.循环链表的表中最后一个结点的指针域指向ቤተ መጻሕፍቲ ባይዱ结点,整个链表形成一个环,而单链 表不是。
单链表的构造函数:
LinkList() { length=0; head=new Node; head->next=NULL; }
单向循环链表的构造和插入 第一个结点的函数
Clist(){ length=0; head=new node; head->next=NULL; } Bool Clist::InsertFirst(int data){ if(length!=0) return false; node* newnode=new node; newnode->data=data; newnode->next=head; head->next=newnode; length++; return true; }
LOGO
几种典型线性表的链式存储结构的比较
/moban
1. 单链表
2. 双向链表
3. 循环链表
/moban
单链表简介
单链表是一种链式存储结构,由存储数据元素信息的域 (数据域)和一个存储直接后继位置的域(指针域)组 成。我们通常在单链表的第一个结点之前附设一个结点 ,称为头结点。它可以存放数据信息也可以不存放。
单链表的插入过程分为三步,第一步是建立新的结点, 第二步是改变新的结点的指向,最后是改变之前结点的 指向。其中指针域的改变用代码表达就是: s->next=p->next; p->next=s;
单链表插入图解
/moban
单链表删除图解
单链表的删除仅需修改结点的指针域即可,用指 针语句为: p->next=p->next->next;
循环链表的插入函数过程图解
/moban
双向链表与单链表的对比
1.从结构上来讲,双向链表的普通的结点有两个指针域分别指向 它的前驱和后继,而单链表只有指向后继结点的指针域。
单链表的构造函数:
LinkList() { length=0; head=new Node; head->next=NULL; }
循环链表的插入函数
bool Clist::Insert(int position,int data) { if(length==0) { InsertFirst(data); return true; } if(position<1||position>length+1) return false; int i=1; node* p=head;
循环链表与单链表的对比
2.若在循环链表中设立 尾指针而不是头指针, 那么两个动态链表的合 并的时间复杂度仅为 O(1),而单链表的合 并的时间复杂度基本上 是O(a.length+b.length) 3.从两种链表的插入和 删除操作上来看,单链 表的临时指针p的循环条 件为p是否为空,而对于 单向循环链表临时指针p 的循环条件为是否等于 头指针。他们的时间复 杂度是一致的,都为 O(n)
/moban
双向链表与单链表的析构函数对比
~LinkList() ~Dlist() { { Node* temp=NULL; while(head->next) while(head->next) { { dnode* p=head; temp=head->next; head->next=temp->next; p=p->next; delete temp; head->next=p->next; } delete p; delete head; } }