




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
2022/11/171数据结构课件西北大学计算机系本演示文稿可能包含观众讨论和即席反应。使用PowerPoint可以跟踪演示时的即席反应,在幻灯片放映中,右键单击鼠标请选择“会议记录”选择“即席反应”选项卡必要时输入即席反应单击“确定”撤消此框此动作将自动在演示文稿末尾创建一张即席反应幻灯片,包括您的观点。
2022/11/101数据结构课件西北大学计算机系2022/11/172第2章
线性表
2.1线性表的概念及运算2.2线性表的顺序存储2.3线性表的链式存储2.4一元多项式的表示及相加2022/11/102第2章线性表2022/11/1732.1线性表的概念及运算2.1.1线性表的逻辑结构
2.1.2线性表的抽象数据类型定义
2022/11/1032.1线性表的概念及运算2.1.12022/11/174线性表的定义线性表(LinearList)是由n(n≥0)个类型相同的数据元素a1,a2,…,an组成的有限序列,记做(a1,a2,…,ai-1,ai,ai+1,…,an)。
数据元素之间是一对一的关系,即每个数据元素最多有一个直接前驱和一个直接后继。线性表的逻辑结构图为:
2022/11/104线性表的定义线性表(LinearLi2022/11/175线性表的特点同一性:线性表由同类数据元素组成,每一个ai必须属于同一数据对象。有穷性:线性表由有限个数据元素组成,表长度就是表中数据元素的个数。有序性:线性表中相邻数据元素之间存在着序偶关系<ai,ai+1>。
2022/11/105线性表的特点2022/11/1762.1.2线性表的抽象数据类型定义抽象数据类型定义
:ADTLinearList{
数据元素:D={ai|ai∈D0,i=1,2,…,n
n≥0,D0为某一数据对象}
关系:S={<ai,ai+1>|ai,ai+1∈D0,i=1,2,…,n-1}基本操作:(1)InitList(L)操作前提:L为未初始化线性表。 操作结果:将L初始化为空表。(2)DestroyList(L)操作前提:线性表L已存在。操作结果:将L销毁。(3)ClearList(L)操作前提:线性表L已存在
。操作结果:将表L置为空表。
………}ADT
LinearList2022/11/1062.1.2线性表的抽象数据类型定义2022/11/1772.2线性表的顺序存储2.2.1线性表的顺序存储结构
2.2.2线性表顺序存储结构上的基本运算
2022/11/1072.2线性表的顺序存储2.2.12022/11/178顺序存储结构的定义
线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素,使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系。采用顺序存储结构的线性表通常称为顺序表。假设线性表中每个元素占k个单元,第一个元素的地址为loc(a1),则第k个元素的地址为:
loc(ai)=loc(a1)+(i-1)×k 2022/11/108顺序存储结构的定义 线性表的顺序2022/11/179顺序存储结构示意图存储地址
内存空间状态
逻辑地址
Loc(a1)a11Loc(a1)+(2-1)ka2
2…
……loc(a1)+(i-1)kai
i…
……loc(a1)+(n-1)kan
n...
loc(a1)+(maxlen-1)k
空闲2022/11/109顺序存储结构示意图存储地址内存空间状2022/11/1710顺序存储结构的C语言定义#define maxsize=线性表可能达到的最大长度;typedefstruct{ElemTypeelem[maxsize];/*线性表占用的数组空间*/intlast;
/*记录线性表中最后一个元素在数组elem[]
中的位置(下标值),空表置为-1*/}SeqList;
注意区分元素的序号和数组的下标,如a1的序号为1,而其对应的数组下标为0。
2022/11/1010顺序存储结构的C语言定义#defin2022/11/17112.2.2线性表顺序存储结构的基本运算线性表的基本运算:查找操作
插入操作
删除操作顺序表合并算法线性表顺序存储结构的优缺点分析2022/11/10112.2.2线性表顺序存储结构的基2022/11/1712查找操作线性表的两种基本查找运算按序号查找GetData(L,i):要求查找线性表L中第i个数据元素,其结果是L.elem[i-1]或L->elem[i-1]。按内容查找Locate(L,e):
要求查找线性表L中与给定值e相等的数据元素,其结果是:若在表L中找到与e相等的元素,则返回该元素在表中的序号;若找不到,则返回一个“空序号”,如-1。线性表的查找运算算法描述为:2022/11/1012查找操作线性表的两种基本查找运算2022/11/1713线性表的查找运算intLocate(SeqListL,ElemTypee){ i=0;/*i为扫描计数器,初值为0,即从第一个元素开始比较*/while((i<=L.last)&&(L.elem[i]!=e)
)i++;/*顺序扫描表,直到找到值为key的元素,或扫描到表尾而没找到*/if(i<=L.last)return(i);/*若找到值为e的元素,则返回其序号*/
else return(-1);/*若没找到,则返回空序号*/}2022/11/1013线性表的查找运算intLoca2022/11/1714插入操作
线性表的插入运算是指在表的第i(1≤i≤n+1)个位置,插入一个新元素e,使长度为n的线性表(e1,…,ei-1,ei,…,en)变成长度为n+1的线性表(e1,…,ei-1,e,ei,…,en)。
线性表的插入运算算法。2022/11/1014插入操作线性表的插入运算是指在表的2022/11/1715插入算法示意图
已知:线性表
(4,9,15,28,30,30,42,51,62),需在第4个元素之前插入一个元素“21”。则需要将第9个位置到第4个位置的元素依次后移一个位置,然后将“21”插入到第4个位置,序号移动元素插入元素12345678109491528303042516249152830304262514915212830304262512022/11/1015插入算法示意图 已知:线性表(4,2022/11/1716插入运算intInsList(SeqList*L,inti,ElemTypee){intk;if((i<1)||(i>L->last+2))/*首先判断插入位置是否合法*/{printf(“插入位置i值不合法”);return(ERROR);}if(L->last>=maxsize-1){printf(“表已满无法插入”);return(ERROR);}for(k=L->last;k>=i-1;k--)/*为插入元素而移动位置*/L->elem[k+1]=L->elem[k];L->elem[i-1]=e;/*在C语言中数组第i个元素的下标为i-1*/
L->last++;return(OK);}
算法演示(此处连接算法演示程序)。2022/11/1016插入运算intInsList(S2022/11/1717删除操作
线性表的删除运算是指将表的第i(1≤i≤n)个元素删去,使长度为n的线性表
(e1,…,ei-1,ei,ei+1,…,en),变成长度为n-1的线性表(e1,…,ei-1,
ei+1,…,en)。
算法思路示意
算法实现2022/11/1017删除操作 线性表的删除运2022/11/1718删除算法示意
将线性表(4,9,15,21,28,30,30,42,51,62)中的第5个元素删除。
序号123456781094915212830304262514915213030425162删除28后2022/11/1018删除算法示意 将线性表(4,9,152022/11/1719删除算法
intDelList(SeqList*L,inti,ElemType*e)/*在顺序表L中删除第i个数据元素,并用指针参数e返回其值*/{intk;if((i<1)||(i>L->last+1)){printf(“删除位置不合法!”);return(ERROR);}*e=L->elem[i-1];
/*将删除的元素存放到e所指向的变量中*/for(k=i;i<=L->last;k++)L->elem[k-1]=L->elem[k];/*将后面的元素依次前移*/L->last--;return(OK);}
2022/11/1019删除算法intDelList(2022/11/1720合并算法已知
:有两个顺序表LA和LB,其元素均为非递减有序排列,编写一个算法,将它们合并成一个顺序表LC,要求LC也是非递减有序排列。
算法思想:设表LC是一个空表,为使LC也是非递减有序排列,可设两个指针i、j分别指向表LA和LB中的元素,若LA.elem[i]>LB.elem[j],则当前先将LB.elem[j]插入到表LC中,若LA.elem[i]≤LB.elem[j],当前先将LA.elem[i]插入到表LC中,如此进行下去,直到其中一个表被扫描完毕,然后再将未扫描完的表中剩余的所有元素放到表LC中。算法实现此处连接算法演示2022/11/1020合并算法已知
:有两个顺序表LA和L2022/11/1721顺序表合并算法实现voidmerge(SeqList*LA,SeqList*LB,SeqList*LC){i=0;j=0;k=0;while(i<=LA->last&&j<=LB->last)if(LA->elem[i]<=LB->elem[j])
{
LC->elem[k]=LA->elem[i];i++;k++;}
else
{
LC->elem[k]=LB->elem[j];j++;k++;}while(i<=LA->last)
/*当表LA长则将表LA余下的元素赋给表LC*/
{
LC->elem[k]=LA->elem[i];
i++;k++;}while(j<=LB->last)/*当表LB长则将表LB余下的元素赋给表LC*/
{
LC->elem[k]=LB->elem[j];
j++;k++;}
LC->last=LA->last+LB->last;}2022/11/1021顺序表合并算法实现voidmerg2022/11/1722顺序存储结构的优点和缺点优点:1.无需为表示结点间的逻辑关系而增加额外的存储空间;
2.可方便地随机存取表中的任一元素。
缺点:1.插入或删除运算不方便,除表尾的位置外,在表的其它位置上进行插入或删除操作都必须移动大量的结点,其效率较低;
2.由于顺序表要求占用连续的存储空间,存储分配只能预先进行静态分配。因此当表长变化较大时,难以确定合适的存储规模。2022/11/1022顺序存储结构的优点和缺点优点:2022/11/17232.3线性表的链式存储链表定义:
采用链式存储结构的线性表称为链表。现在我们从两个角度来讨论链表:1.从实现角度看,链表可分为动态链表和静态链表;2.从链接方式的角度看,链表可分为单链表、循环链表和双链表。
2022/11/10232.3线性表的链式存储链表定义:2022/11/17242.3.1单链表
2.3.2单链表上的基本运算
2.3.3循环链表
2.3.4双向链表
*2.3.5静态链表
2.3.6顺序表和链表的比较链表2022/11/10242.3.1单链表链表2022/11/17252.3.1单链表
结点(Node)为了正确地表示结点间的逻辑关系,必须在存储线性表的每个数据元素值的同时,存储指示其后继结点的地址(或位置)信息,这两部分信息组成的存储映象叫做结点(Node)。单链表:链表中的每个结点只有一个指针域,我们将这种链表称为单链表。单链表包括两个域:数据域用来存储结点的值;指针域用来存储数据元素的直接后继的地址(或位置)。头指针:指向链表头结点的指针。2022/11/10252.3.1单链表结点(N2022/11/1726单链表的示例图头指针H存储地址数据域指针域1D437B1313C119HNULL25F3731A737G1943E25312022/11/1026单链表的示例图头指针H存储地址数据域2022/11/1727带头结点的单链表示意图有时为了操作的方便,还可以在单链表的第一个结点之前附设一个头结点。带头结点的空单链表
带头结点的单链表
∧Ha1a2…Han
∧2022/11/1027带头结点的单链表示意图有时为了操作的2022/11/1728单链表的存储结构描述typedefstructNode/*结点类型定义*/{ElemTypedata;
structNode*next;}Node,*LinkList;/*LinkList为结构指针类型*/
2022/11/1028单链表的存储结构描述typedef2022/11/17292.3.2单链表上的基本运算线性表的基本运算:建立单链表
单链表查找
单链表插入操作
单链表删除
算法应用示例:求单链表的长度
求两个集合的差
2022/11/10292.3.2单链表上的基本运算线性2022/11/1730建立单链表头插法建表
算法描述:从一个空表开始,重复读入数据,生成新结点,将读入数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头结点之后,直至读入结束标志为止。c1∧sL∧L
ci-1∧c2c1∧cis…c1∧2022/11/1030建立单链表头插法建表c1∧sL∧2022/11/1731头插法建表算法LinklistCreateFromHead(){LinkListL;Node
*s;intflag=1;
/*设置一个标志,初值为1,当输入“$”时,flag为0,建表结束*/L=(Linklist)malloc(sizeof(Node));/*为头结点分配存储空间*/
L->next=NULL;while(flag){c=getchar();if(c!=’$’)/*为读入的字符分配存储空间*/{s=(Node*)malloc(sizeof(Node));s->data=c;s->next=L->next;L->next=s;}else
flag=0;}}
2022/11/1031头插法建表算法LinklistC2022/11/1732尾插法建表C1
∧sr∧Lc1rsc2∧Lc1∧rsL2022/11/1032尾插法建表C12022/11/1733尾插法建表算法LinklistCreateFromTail()/*将新增的字符追加到链表的末尾*/{LinkListL;Node*r,*s;intflag=1;
L=(Node*)malloc(sizeof(Node));/*为头结点分配存储空间*/L->next=NULL;r=L;/*r指针始终动态指向链表的当前表尾*/while(flag)/*标志,初值为1。输入“$”时flag为0,建表结束*/
{ c=getchar();
if(c!=’$’){s=(Node*)malloc(sizeof(Node));s->data=c;r->next=s;r=s}else{flag=0;r->next=NULL;}}}2022/11/1033尾插法建表算法LinklistC2022/11/1734单链表查找按序号查找
算法描述:设带头结点的单链表的长度为n,要查找表中第i个结点,则需要从单链表的头指针L出发,从头结点(L->next)开始顺着链域扫描,用指针p指向当前扫描到的结点,初值指向头结点(pL->next),用j做记数器,累计当前扫描过的结点数(初值为0),当j=i时,指针p所指的结点就是要找的第i个结点。算法实现,算法演示。 2022/11/1034单链表查找按序号查找2022/11/1735按序号查找算法实现/*在带头结点的单链表L中查找第i个结点,若找到(1≤i≤n),则返回该结点的存储位置;否则返回NULL*/Node*Get(LinkListL,inti){Node*p;
p=L;j=0;/*从头结点开始扫描*/while((p->next!=NULL)&&(j<i){p=p->next;j++;/*扫描下一结点*/}/*已扫描结点计数器*/if(i==j)returnp;/*找到了第i个结点*/elsereturnNULL;/*找不到,i≤0或i>n*/}2022/11/1035按序号查找算法实现/*在带头结点2022/11/1736按值查找
算法描述:按值查找是指在单链表中查找是否有结点值等于e的结点,若有的话,则返回首次找到的其值为e的结点的存储位置,否则返回NULL。查找过程从单链表的头指针指向的头结点出发,顺着链逐个将结点的值和给定值e作比较。算法实现,算法演示。单链表查找2022/11/1036按值查找单链表查找2022/11/1737按值查找算法实现/*在带头结点的单链表L中查找其结点值等于key的结点,若找到则返回该结点的位置p,否则返回NULL*/Node*Locate(LinkListL,ElemTypekey){Node*p;p=L->next;/*从表中第一个结点比较*/while(p!=NULL)if(p->data!=key) p=p->next;elsebreak;/*找到结点key,退出循环*/returnp;}2022/11/1037按值查找算法实现/*在带头结点的2022/11/1738单链表插入操作算法描述:
要在带头结点的单链表L中第i个数据元素之前插入一个数据元素e,需要首先在单链表中找到第i-1个结点并由指针pre指示,然后申请一个新的结点并由指针s指示,其数据域的值为e,并修改第i-1个结点的指针使其指向s,然后使s结点的指针域指向第i个结点。esa1……an∧ai-1aiespreLa1……an∧preai-1ai2022/11/1038单链表插入操作算法描述:esa1……2022/11/1739单链表插入操作算法实现voidInsList(LinkListL,inti,ElemTypee){/*在带头结点的单链表L中第i个结点之前插入值为e的新结点。*/
Node*pre,*s;
pre=L;intk=0;while(pre!=NULL&&k<i-1)/*先找到第i-1个数据元素的存储位置,使指针Pre指向它*/
{pre=pre->next;
k=k+1;}if(k!=i-1){printf(“插入位置不合理!”);return;}s=(Node*)malloc(sizeof(Node));/*为e申请一个新的结点*/s->data=e;/*将待插入结点的值e赋给s的数据域*/s->next=pre->next;pre->next=s;}
2022/11/1039单链表插入操作算法实现voidIn2022/11/1740单链表删除算法描述: 欲在带头结点的单链表L中删除第i个结点,则首先要通过计数方式找到第i-1个结点并使p指向第i-1个结点,而后删除第i个结点并释放结点空间。pa1…ai-1ai…an∧pa1…L…an∧ai-1aiai+1rL2022/11/1040单链表删除算法描述:pa1…ai-12022/11/1741单链表删除算法实现voidDelList(LinkListL,inti,ElemType*e)/*在带头结点的单链表L中删除第i个元素,并保存其值到变量*e中*/{
Node*p,*r;p=L;intk=0;
while(p->next!=NULL&&k<i-1)/*寻找被删除结点i的前驱结点*/{p=p->next;k=k+1;}if(k!=i-1)/*即while循环是因为p->next=NULL而跳出的*/{printf(“删除结点的位置i不合理!”);returnERROR;}r=p->next;p->next=p->next->next/*删除结点r*/free(r);/*释放被删除的结点所占的内存空间*/}2022/11/1041单链表删除算法实现voidDelL2022/11/1742求单链表的长度
算法描述:可以采用“数”结点的方法来求出单链表的长度,用指针p依次指向各个结点,从第一个元素开始“数”,一直“数”到最后一个结点(p->next=NULL)。
int ListLength(LinkListL)/*L为带头结点的单链表*/{Node*p;p=L->next; j=0;/*用来存放单链表的长度*/while(p!=NULL){ p=p->next;j++;}returnj;}算法演示链接。2022/11/1042求单链表的长度 算法描述:可以采用“2022/11/1743两个有序单链表的合并有两个单链表LA和LB,其元素均为非递减有序排列,编写一个算法,将它们合并成一个单链表LC,要求LC也是非递减有序排列。要求:利用新表LC利用现有的表LA和LB中的元素结点空间,而不需要额外申请结点空间。例如LA=(2,2,3),LB=(1,3,3,4),则LC=(1,2,2,3,3,3,4)。
【算法描述】要求利用现有的表LA和LB中的结点空间来建立新表LC,可通过更改结点的next域来重建新的元素之间的线性关系,为保证新表仍然递增有序,可以利用尾插入法建立单链表的方法,只是新建表中的结点不用malloc,而只需要从表LA和LB中选择合适的点插入到新表LC中即可。2022/11/1043两个有序单链表的合并有两个单链表LA2022/11/17442022/11/10442022/11/1745两个有序单链表的合并的算法实现LinkListMergeLinkList(LinkListLA,LinkListLB)/*将递增有序的单链表LA和LB合并成一个递增有序的单链表LC*/{Node*pa,*pb;LinkListLC;/*将LC初始置空表。pa和pb分别指向两个单链表LA和LB中的第一个结点,r初值为LC*/pa=LA->next;pb=LB->next;LC=LA;LC->next=NULL;r=LC; /*初始化操作*/2022/11/1045两个有序单链表的合并的算法实现Lin2022/11/1746两个有序单链表的合并的算法实现(续)/*当两个表中均未处理完时,比较选择将较小值结点插入到新表LC中。*/
while(pa!=NULL&&pb!=NULL) {if(pa->data<=pb->data){r->next=pa;r=pa;pa=pa->next;}else{r->next=pb;r=pb;pb=pb->next;}}if(pa)/*若表LA未完,将表LA中后续元素链到新表LC表尾*/r->next=pa;else /*否则将表LB中后续元素链到新表LC表尾*/r->next=pb;free(LB);return(LC);}/*MergeLinkList*/2022/11/1046两个有序单链表的合并的算法实现(续)2022/11/17472.3.3循环链表
循环链表(CircularLinkedList)
是一个首尾相接的链表。特点:将单链表最后一个结点的指针域由NULL改为指向头结点或线性表中的第一个结点,就得到了单链形式的循环链表,并称为循环单链表。在循环单链表中,表中所有结点被链在一个环上。
带头结点循环单链表示意图。2022/11/10472.3.3循环链表 循环链表(C2022/11/1748带头结点的循环单链表示意图
La1……ai-1aianLa1……ai-1aianrear*(rear->next)*rear空链表带头结点的一般形式
带尾结点的一般形式
2022/11/1048带头结点的循环单链表示意图2022/11/1749循环单链表合并为一个循环单链表
已知:有两个带头结点的循环单链表LA、LB,编写一个算法,将两个循环单链表合并为一个循环单链表,其头指针为LA。 算法思想:先找到两个链表的尾,并分别由指针p、q指向它们,然后将第一个链表的尾与第二个表的第一个结点链接起来,并修改第二个表的尾Q,使它的链域指向第一个表的头结点。
2022/11/1049循环单链表合并为一个循环单链表 已知2022/11/1750循环单链表合并算法实现LinkListmerge_1(LinkListLA,LinkListLB)/*此算法将两个链表的首尾连接起来*/{Node*p,*q;p=LA;q=LB;while(p->next!=LA)p=p->next; /*找到表LA的表尾*/while(q->next!=LB)q=q->next; /*找到表LB的表尾*/q->next=LA;/*修改表LB的尾指针,使之指向表LA的头结点*/p->next=LB->next;/*修改表LA的尾指针,使之指向表LB中的第一个结点*/ free(LB);return(LA);}2022/11/1050循环单链表合并算法实现LinkLis2022/11/17512.3.4双向链表
双向链表:在单链表的每个结点里再增加一个指向其前趋的指针域prior。这样形成的链表中就有两条方向不同的链,我们称之为双
(向)链表
(DoubleLinkedList)。双向链表的结构定义:
typedefstructDnode {ElemTypedata;
structDNode*prior,*next;
}DNode, *DoubleList;2022/11/10512.3.4双向链表双向链表:2022/11/1752双链表的结构定义双链表的结点结构后继指针域priordatanext前驱指针域数据域2022/11/1052双链表的结构定义双链表的结点结构后2022/11/1753双向循环链表示意图a1a2a3LL空的双向循环链表
非空的双向循环链表
2022/11/1053双向循环链表示意图a12022/11/1754双向链表的前插操作算法描述:欲在双向链表第i个结点之前插入一个的新的结点,则指针的变化情况如图所示。es①②③④…bpa…2022/11/1054双向链表的前插操作算法描述:欲在双向2022/11/1755双向链表的前插操作算法实现void
DlinkIns(DoubleListL,inti,ElemTypee)
{DNode*s,*p; …/*首先检查待插入的位置i是否合法*/
…/*若位置i合法,则让指针p指向它*/s=(DNode*)malloc(sizeof(DNode));if(s){s->data=e;s->prior=p->prior;p->prior->next=s;s->next=p;p->prior=s;returnTRUE;}
else
returnFALSE;}
算法演示连接。2022/11/1055双向链表的前插操作算法实现void2022/11/1756双向链表的删除操作算法描述:欲删除双向链表中的第i个结点,则指针的变化情况如图所示。abcp②①……2022/11/1056双向链表的删除操作算法描述:欲删除双2022/11/1757双向链表的删除操作算法实现int
DlinkDel(DoubleListL,inti,ElemType*e)
{ DNode*p; …/*首先检查待插入的位置i是否合法*/
…/*若位置i合法,则让指针p指向它*/ *e=p->data; p->prior->next=p->next; p->next->prior=p->prior; free(p); returnTRUE;}2022/11/1057双向链表的删除操作算法实现int D2022/11/1758*2.3.5静态链表基本概念:
游标实现链表的方法:定义一个较大的结构数组作为备用结点空间(即存储池)。当申请结点时,每个结点应含有两个域:data域和next域。data域存放结点的数据信息,next域为游标指示器,指示后继结点在结构数组中的相对位置(即数组下标)。数组的第0个分量可以设计成表的头结点,头结点的next域指示了表中第一个结点的位置,为0表示静态单链表的结束。我们把这种用游标指示器实现的单链表叫做静态单链表(StaticLinkedList)。静态链表的结构定义,静态链表的插入和删除操作示例。基本操作:初始化、分配结点与结点回收、前插操作、删除。
2022/11/1058*2.3.5静态链表基本概念:2022/11/1759静态链表的结构定义#defineMaxsize=链表可能达到的最大长度typedefstruct{ElemTypedata;intcursor;}Component,StaticList[Maxsize];
2022/11/1059静态链表的结构定义#define2022/11/1760静态链表的插入和删除操作示例已知:线性表
a,b,c,d,f,g,h,i),Maxsize=110123456789100123456789101a2b3c4d9f6g8h8i0e51a2b3c4d9f6g7h8i0e51a2b3c4d5f6g7h8i0012345678910(a)初始化(b)插入e后(c)删除h后2022/11/1060静态链表的插入和删除操作示例已知:线2022/11/1761静态链表初始化算法描述:初始化操作是指将这个静态单链表初始化为一个备用静态单链表。设space为静态单链表的名字,av为备用单链表的头指针,其算法如下:voidinitial(StaticListspace,int*av){intk;space[0]->cursor=0;/*设置静态单链表的头指针指向位置0*/for(k=0;k<Maxsize-1;k++) space[k]->cursor=k+1;/*连链*/space[Maxsize-1].cursor
=0;/*标记链尾*/*av=1;/*设置备用链表头指针初值*/}
2022/11/1061静态链表初始化算法描述:初始化操作是2022/11/1762静态链表分配结点与结点回收分配结点intgetnode(int*av)/*从备用链表摘下一个结点空间,分配给待插入静态链表中的元素*/{inti=*av;*av=space[*av].cur;returni;}结点回收voidfreenode(int*av,intk)/*将下标为k的空闲结点插入到备用链表*/{space[k].cursor=*av;*av=k;}2022/11/1062静态链表分配结点与结点回收分配结点2022/11/17632.4一元多项式的表示及相加一元多项式可按升幂的形式写成:Pn(x)=p0+p1xe1+p2xe2+…+pnxen,其中ei为第i项的指数,pi是指数ei的项的系数,(且1≤e1≤e2≤…≤en)假设Qm(x)是一个一元多项式,则它也可以用一个线性表Q来表示。即:Q=(q0,q1,q2,…,qm)若假设m<n,则两个多项式相加的结果Rn(x)=Pn(x)+Qm(x),也可以用线性表R来表示:R=(p0+q0,p1+q1,,p2+q2,…,pm+qm
,pm+1,…,pn)2022/11/10632.4一元多项式的表示及相加一元2022/11/1764一元多项式的存储一元多项式的顺序存储表示一元多项式的链式存储表示2022/11/1064一元多项式的存储一元多项式的顺序存2022/11/1765一元多项式的顺序存储表示1一元多项式Pn(x)的顺序表示有两种。法1、只存储该一元多项式各项的系数,每个系数所对应的指数项则隐含在存储系数的顺序表的下标中。即p[0]存系数p0,对应为x0的系数,p[1]存系数p1,对应为x1的系数,……p[n]存系数pn,对应为xn的系数。采用这种存储方法使得多项式的相加运算的算法定义十分简单,只需将下标相同的单元的内容相加即可。适合于存储表示非零系数多的多项式。2022/11/1065一元多项式的顺序存储表示1一元多项式2022/11/1766一元多项式的顺序存储表示2法2、采用只存储非零项的方法,此时每个非零项需要存储:非零项系数和非零项指数。适合存储表示非零项少的多项式。piei┋┋图2.19一元多项式只存非零项存储示意图2022/11/1066一元多项式的顺序存储表示2法2、采用2022/11/1767一元多项式的链式存储表示在链式存储中,对一元多项式只存非零项,则该多项式中每一非零项由两部分构成(指数项和系数项),用单链表存储表示的结点结构为:用单链表存储多项式的结点结构如下:
structPolynode { intcoef;intexp;Polynode*next;}Polynode,*Polylist;
系数coef指数exp指针next2022/11/1067一元多项式的链式存储表示在链式存储2022/11/1768建立一元多项式链式存储的算法【算法思想】通过键盘输入一组多项式的系数和指数,用尾插法建立一元多项式的链表。以输入系数0为结束标志,并约定建立多项式链表时,总是按指数从小到大的顺序排列。【算法描述】Polylistpolycreate(){Polynode*head,*rear,*s; intc,e; rear=head=(Polynode*)malloc(sizeof(Polynode)); /*建立多项式的头结点,rear始终指向单链表的尾*/ scanf(“%d,%d”,&c,&e);/*键入多项式的系数和指数项*/ while(c!=0) /*若c=0,则代表多项式的输入结束*/ {s=(Polynode*)malloc(sizeof(Polynode)); /*申请新的结点*/s->coef=c;s->exp=e;rear->next=s; /*在当前表尾做插入*/rear=s; scanf(“%d,%d”,&c,&e);}rear->next=NULL;/*将表的最后一个结点的next置NULL,以示表结束*/return(head);}2022/11/1068建立一元多项式链式存储的算法【算法思2022/11/1769一元多项式的单链表表示示意图说明:图示分别为多项式
A(x)=7+3x+9x8+5x17 B(x)=8x+22x7-9x8
-17031517∧9881-1227-98∧
2022/11/1069一元多项式的单链表表示示意图说明:图2022/11/1770两个一元多项式相加运算规则:两个多项式中所有指数相同的项的对应系数相加,若和不为零,则构成“和多项式”中的一项;所有指数不相同的项均复抄到“和多项式”中。算法实现,算法演示若p->exp<q->exp,则结点p所指的结点应
是“和多项式”中的一项,令指针p后移;若p->exp>q->exp,则结点q所指的结点应是“和多项式”中的一项,将结点q插入在结点p之前,且令指针q在原来的链表上后移;若p->exp=q->exp,则将两个结点中的系数相加,当和不为零时修改结点p的系数域,释放q结点;若和为零,则和多项式中无此项,从A中删去p结点,同时释放p和q结点。2022/11/1070两个一元多项式相加运算规则:两个多项2022/11/1771两个多项式相加算法实现voidpolyadd(Polylistpolya;Polylistpolyb){
……/*p和q分别指向polya和polyb链表中的当前计算结点*/
……/*pre指向和多项式链表中的尾结点*/whilep!=NULL&&q!=NULL)
{if
(p->exp<q->exp)
{…/*将p结点加入到和多项式中*/}elseif(p->exp==q->exp)
{…/*若指数相等,则相应的系数相加。若系数为0则删除p,q节点*/}
else{…/*将q结点加入到和多项式中*/}}
…../*将多项式polya或polyb中剩余的结点加入到和多项式中*/}2022/11/1071两个多项式相加算法实现voidp2022/11/17722.5顺序表和链表的比较
1.基于空间的考虑
2.基于时间的考虑
3.基于语言的考虑
2022/11/10722.5顺序表和链表的比较
1.2022/11/1773线性表链式存储方式的比较
操作名称链表名称找表头结点找表尾结点找P结点前驱结点带头结点单链表LL->next时间耗费O(1)一重循环时间耗费O(n)顺P结点的next域无法找到P结点的前驱带头结点循环单链表(头指针)LL->next时间耗费O(1)一重循环时间耗费O(n)顺P结点的next域可以找到P结点的前驱时间耗费O(n)带尾指针的循环单链表RR->nextO(1)R时间耗费O(1)顺P结点的next域可以找到P结点的前驱时间耗费O(n)带头结点双向循环链表LL->nextO(1)L->prior时间耗费O(1)P->prior时间耗费O(1)2022/11/1073线性表链式存储方式的比较2022/11/17742.6总结与提高
主要知识点
1、线性表的特征:线性表中每个数据元素有且仅有一个直接前驱和一个直接后继,第一个结点无前驱,最后一个结点无后继。2、线性表存储方式:线性表顺序存储(顺序表):采用静态分配方式,借助于C语言的数组类型,申请一组连续的地址空间,依次存放表中元素,其逻辑次序隐含在存储顺序之中。2022/11/10742.6总结与提高
主要知识点2022/11/17752.6总结与提高线性表链式存储(链表):采用动态分配方式,借助于C语言的指针类型,动态申请与动态释放地址空间,故链表中的各结点的物理存储可以是不连续的。当表长度变化时仅需适当变化指针的联接,适合于表中元素个数动态变化。3、单链表的操作特点:⑴顺链操作技术⑵指针保留技术4、链表处理中的相关技术2022/11/10752.6总结与提高线性表链式存储(2022/11/1776典型题例
例1:已知顺序表L中的数据元素类型为int。设计算法将其调整为左右两部分,左边的元素(即排在前面的)均为奇数,右边所有元素(即排在后面的)均为偶数,并要求算法的时间复杂度为O(n),空间复杂度为O(1)。2022/11/1076典型题例
例1:已知顺序表L中的数据2022/11/1777例1【问题分析】初见此题,可能会想到额外申请1个顺序表空间,之后依次从顺序表L中选择奇数放入新表前部分,选择偶数放在新表的后半部分。但是题目要求空间复杂度为O(1),很显然上述方法是不可行的。既然要求空间复杂度为O(1),说明只能借助1个辅助空间。分析题目要求,其实我们只需要将位于表左半部分的偶数与位于表右半部分的奇数通过一个辅助变量进行交换即可,为此我们可以设置两个位置指示器i和j,i初值为0,j初值为L->last,当L->elem[i]为偶数,L->elem[j]为奇数时,则将L->elem[i]与L->elem[j]交换;否则,L->elem[i]为奇数,i++,L->elem[j]为偶数,j++。这样既可以保证算法的时间复杂度为O(n),亦可保证空间复杂度为O(1)。2022/11/1077例1【问题分析】初见此题,可能会想到2022/11/1778【算法描述】
AdjustSqlist(SeqList*L)/*{inti=0,j=L->last;while(i<j){while(L->elem[i]%2!=0)i++;/*从表的左半部分开始检测,若为奇数,则i加1,直到找到偶数为止*/while(L->elem[j]%2==0)j--;/*从表的右半部分开始检测,若为偶数,则j减1,直到找到奇数为止*/if(i<j){t=L->elem[i];L->elem[i]=L->elem[j];L->elem[j]=t;}/*交换*/}}/*endofAdjustSqlist*/2022/11/1078【算法描述】
AdjustSqlis2022/11/1779例2:算法实现带头结点单链表的就地逆置问题。【问题分析】逆置就是使得表中内容由原来的(a1,a2,…,ai-1,ai,ai+1,…,an)变为(an,an-1,…,ai+1,ai,ai-1,…,a1)。就地逆置就是不需要额外申请结点空间,只需要利用原有的表中的节点空间。若对顺序表中的元素进行逆置,可以借助于“交换”前后相应元素;对单链表中的元素进行逆置,则不能按“交换”思路,因为对于链表中第i个结点需要顺链查找第n-i+1(链表长度为n)个结点,逆置链表的时间复杂度将达O(n2)。2022/11/1079例2:算法实现带头结点单链表的就地逆2022/11/1780算法思路:逆置后的单链表初始为空,表中的结点不是新生成的,而是从原链表中依次“删除”,再逐个头插入到逆置表中(类同算法2.5头查法创建链表)。设逆置链表的初态为空表,“删除”已知链表中的第一个结点,然后将它“插入”到逆置链表的“表头”,即使它成为逆置链表中“新”的第一个结点,如此循环,直至原链表为空表止。根据单链表的特点,通过头指针L我们可以顺着每个结点的next域,依次访问到a1,a2,a3…an-1,an;2)我们可以借鉴前面讲到过的头插入法建链表的方法,因为头插入法建链表又称为逆序建表法3)唯一不同的是,我们不需要重新申请结点空间,而只需要从原有单链表上依次“摘下”结点,之后插入到单链表头结点和表中第一个结点之间即可。如图所示2022/11/1080算法思路:逆置后的单链表初始为空,表2022/11/1781…a1…an∧a2ai(a)初始状态Lp为原链表当前处理结点断开L->next,使逆置表初始为空表(b)将单链表L初始为空表…a1…an∧a2ai∧Lpqq指向原链表当前处理结点的下一个p①aia2a1∧L……an∧a3q(c)将p指向的结点插入到逆置表L的表头②2022/11/1081…a1…an∧a2ai(a)2022/11/1782例2【算法描述】voidReverseList(LinkListL)/*逆置带头结点的单链表L*/{p=L->next;/*P为原链表的当前处理结点*/L->next=NULL;/*逆置单链表初始为空表*/while(p!=NULL)/*当原链表未处理完*/{q=p->next;/*q指针保留原链表当前处理结点的下一个结点*/p->next=L->next;L->next=p;/*将当前处理结点p插入到逆置表L的表头*/p=q;/*p指向下一个待插入的结点*/}/*endofwhile*/}/*endofReverstList*/【思考】已知一个带头结点的单链表L,设计算法实现:以表中第一个元素作为标准,将单链表中所有值小于第一个元素的结点均放在第一个元素结点之前,所有值大于第一个元素的结点均放在第一个元素结点之后。(提示:此题可以利用头插法)2022/11/1082例2【算法描述】2022/11/1783例3、建立一个带头结点的线性链表,用以存放输入的二进制数,链表中每个结点的data域存放一个二进制位。并在此链表上实现对二进制数加1的运算。【问题分析】①建链表:带二进制数可用带头结点的单链表存储,第一个结点存储二进制数的最高位,依次存储,最后一个结点存储二进制数的最低位。②二进制加法规则:实现二进制数加1运算,方向从低位往高位找到第一个值为0的位,从该位开始,对后面所有低位进行求反运算。③链表实现二进制加1时,从高位往低位与运算方向正好相反,从第一个结点开始找,找出最后一个值域为0的结点,把该结点值域赋为1,其后所有结点的值域赋为0。④若在链表中未找到值域为0的结点,则表示该二进制数各位均为1,此时,申请一新结点,值域为1,插入到头结点与原链表的第一个结点之间,成为新链表的第一个结点,其后所有结点的值域赋为0。2022/11/1083例3、建立一个带头结点的线性链表,用2022/11/1784【算法描述】
voidBinAdd(LinkListl)/*用带头结点的单链表L存储二进制数,实现加1运算*/{ Node*q,*r,*temp,*s; q=l->next; r=l; while(q!=NULL)/*查找最后一个值域为0的结点*/ {if(q->data==0) r=q;q=q->next; }
2022/11/1084【算法描述】
voidBinAdd2022/11/1785if(r!=l) r->data=1;/*将最后一个值域为0的结点的值域赋为1*/ else/*未找到值域为0的结点*/ { temp=r->next; s=(Node*)malloc(sizeof(Node));/*申请新结点*/ s->data=1;/*值域赋为1*/ s->next=temp; r->next=s;/*插入到头结点之后*/ r=s; } r=r->next; while(r!=NULL)/*将后面的所有结点的值域赋为0*/ {r->data=0; r=r->next;}}/*BinAdd结束*/2022/11/1085if(r!=l)2022/11/1786数据结构课件西北大学计算机系本演示文稿可能包含观众讨论和即席反应。使用PowerPoint可以跟踪演示时的即席反应,在幻灯片放映中,右键单击鼠标请选择“会议记录”选择“即席反应”选项卡必要时输入即席反应单击“确定”撤消此框此动作将自动在演示文稿末尾创建一张即席反应幻灯片,包括您的观点。
2022/11/101数据结构课件西北大学计算机系2022/11/1787第2章
线性表
2.1线性表的概念及运算2.2线性表的顺序存储2.3线性表的链式存储2.4一元多项式的表示及相加2022/11/102第2章线性表2022/11/17882.1线性表的概念及运算2.1.1线性表的逻辑结构
2.1.2线性表的抽象数据类型定义
2022/11/1032.1线性表的概念及运算2.1.12022/11/1789线性表的定义线性表(LinearList)是由n(n≥0)个类型相同的数据元素a1,a2,…,an组成的有限序列,记做(a1,a2,…,ai-1,ai,ai+1,…,an)。
数据元素之间是一对一的关系,即每个数据元素最多有一个直接前驱和一个直接后继。线性表的逻辑结构图为:
2022/11/104线性表的定义线性表(LinearLi2022/11/1790线性表的特点同一性:线性表由同类数据元素组成,每一个ai必须属于同一数据对象。有穷性:线性表由有限个数据元素组成,表长度就是表中数据元素的个数。有序性:线性表中相邻数据元素之间存在着序偶关系<ai,ai+1>。
2022/11/105线性表的特点2022/11/17912.1.2线性表的抽象数据类型定义抽象数据类型定义
:ADTLinearList{
数据元素:D={ai|ai∈D0,i=1,2,…,n
n≥0,D0为某一数据对象}
关系:S={<ai,ai+1>|ai,ai+1∈D0,i=1,2,…,n-1}基本操作:(1)InitList(L)操作前提:L为未初始化线性表。 操作结果:将L初始化为空表。(2)DestroyList(L)操作前提:线性表L已存在。操作结果:将L销毁。(3)ClearList(L)操作前提:线性表L已存在
。操作结果:将表L置为空表。
………}ADT
LinearList2022/11/1062.1.2线性表的抽象数据类型定义2022/11/17922.2线性表的顺序存储2.2.1线性表的顺序存储结构
2.2.2线性表顺序存储结构上的基本运算
2022/11/1072.2线性表的顺序存储2.2.12022/11/1793顺序存储结构的定义
线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素,使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系。采用顺序存储结构的线性表通常称为顺序表。假设线性表中每个元素占k个单元,第一个元素的地址为loc(a1),则第k个元素的地址为:
loc(ai)=loc(a1)+(i-1)×k 2022/11/108顺序存储结构的定义 线性表的顺序2022/11/1794顺序存储结构示意图存储地址
内存空间状态
逻辑地址
Loc(a1)a11Loc(a1)+(2-1)ka2
2…
……loc(a1)+(i-1)kai
i…
……loc(a1)+(n-1)kan
n...
loc(a1)+(maxlen-1)k
空闲2022/11/109顺序存储结构示意图存储地址内存空间状2022/11/1795顺序存储结构的C语言定义#define maxsize=线性表可能达到的最大长度;typedefstruct{ElemTypeelem[maxsize];/*线性表占用的数组空间*/intlast;
/*记录线性表中最后一个元素在数组elem[]
中的位置(下标值),空表置为-1*/}SeqList;
注意区分元素的序号和数组的下标,如a1的序号为1,而其对应的数组下标为0。
2022/11/1010顺序存储结构的C语言定义#defin2022/11/17962.2.2线性表顺序存储结构的基本运算线性表的基本运算:查找操作
插入操作
删除操作顺序
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 门面服装销售合同范本
- 2025建筑工程公司用工合同协议书
- 2025年合同终止与解除的备案流程解析
- 2025耕地流转合同规定
- 语言魅力提升知到课后答案智慧树章节测试答案2025年春北京城市学院
- 2025年智能家居设备采购合同
- 2024年启东市市属事业单位考试真题
- 租赁扶贫工厂合同范本
- 2024年临高县公安局招聘警务辅助人员真题
- 2024年江苏无锡高新区国企全球选聘人才新增岗位笔试真题
- 【化学】常见的盐(第1课时)-2024-2025学年九年级化学下册(人教版2024)
- 公园物业管理
- 新人教版初中英语七至九年级全部课本单词
- 宜宾市新能源产业有限公司招聘笔试冲刺题2025
- 数字化背景下国有企业财会监督体系的构建与实践创新
- 龙游经济开发区下属国资公司招聘笔试冲刺题2025
- 《海上风电设备运输规范》
- 工业园物业管理方案参考范本
- 2024年黑龙江牡丹江中考英语真题及答案
- 《电力基础设施数字化锁控系统技术》
- 应急救护技能(白城医学高等专科学校)知到智慧树答案
评论
0/150
提交评论