DS02_线性表03_单链表
线性表,线性表和链表的区别

线性表,线性表和链表的区别存储类别顺序存储结构单链表存储分配⽅式⽤⼀段连续的存储单元依次存储线性表的数据元素采⽤链式存储结构,⽤⼀组任意的存储单元存放线性表的元素时间性能查找O(1)、插⼊和删除O(n)查找O(n)、插⼊和删除O(1)空间性能需要预分配存储空间,分⼤了浪费,⼩了容易发⽣上溢不需要分配存储空间,只要有就可以分配,元素个数不受限制通过上⾯的对⽐,可以得出⼀些经验性的结论:若线性表需要频繁查找,很少进⾏插⼊和删除操作时,宜采⽤顺序存储结构。
若需要频繁插⼊和删除时,宜采⽤单链表结构。
当线性表中的元素个数变化较⼤或者根本不知道有多⼤时,最好⽤单链表结构,这样可以不需要考虑存储空间的⼤⼩问题。
⽽如果事先知道线性表的⼤致长度,⽤顺序存储结构效率会⾼很多。
线性表、包括顺序表和链表顺序表⾥⾯元素的地址是连续的,链表⾥⾯节点的地址不是连续的,是通过指针连起来的。
简介⼀种逻辑结构,相同数据类型的n个数据元素的有限序列,除第⼀个元素外,每个元素有且仅有⼀个直接前驱,除最后⼀个元素外,每个元素有且仅有⼀个直接后继。
线性表的特点:(1)元素个数有限(2)逻辑上元素有先后次序(3)数据类型相同(4)仅讨论元素间的逻辑关系注:线性表是逻辑结构,顺序表和链表是存储结构。
1.顺序存储顺序表,使⽤数组实现,⼀组地址连续的存储单元,数组⼤⼩有两种⽅式指定,⼀是静态分配,⼆是动态扩展。
注:线性表从1开始,⽽数组从0开始。
优点:随机访问特性,查找O(1)时间,存储密度⾼;逻辑上相邻的元素,物理上也相邻;缺点:插⼊删除需移动⼤量元素。
顺序表相关的操作跟数组有关,⼀般都是移动数组元素。
这⾥说⼀下插⼊和删除时的边界条件,⾸先线性表从1开始,数组从0开始,单纯的⽂件说明不够直接,来看图说话吧。
插⼊时:对于线性表来说最⼩能插⼊的位置是1,最⼤能插⼊的位置是8(=7+1),所以 1<= index <=(7+1);移动数组元素时要注意,for (int i = count; i >= index; i--) { items[i] = items[i-1];}删除时:只能在蓝⾊⽅块之间寻找节点删除,即1 <= index <= 7。
DS03_线性表2

ListNode<type> *p= new ListNode<type> (value, q->next);
assert(p); //p->next=q->next;
q->next=p;
length++; return true; }
head=NULL; if(!l.head)
//复制链表长度
//若链表1为空,返回
return *this;
SIE. BIT
数据结构与算法设计
//为当前链表头结点分配存储 head=new ListNode<type>; if(!head) return *this; //若分配失败返回;之前可加assert
数据结构与算法设计
带头结点的单向链表
head
a1
a2
head
ai-1
ai
ai+1
an n
n
空表
怎样判断带头结点的单向链表是否为空表? 如果:head->nextபைடு நூலகம்== NULL 成立,则为空表。 等价: 如果:head->next != NULL 成立,则不是空表。
SIE. BIT
数据结构与算法设计
数据结构与算法设计
template<class type>
type List<type>::Remove(int i) { //p定位于第i-1个元素结点
ListNode<type> *p=Find(i-1), *q;
DS02线性表习题参考解答

第2章线性表习题参考解答一、简答题1.试描述头指针、头结点、开始结点的区别、并说明头指针和头结点的作用。
【答】头指针:是指向链表中的第一个结点的指针。
头结点:在开始结点之前附加上的一个结点。
开始结点:链表的第一个结点。
头指针是一个指向地址的变量,用于表示一个链表的开始。
引入头结点可以更加方便的进行链表是否为空的判断,同时方便了插入和删除结点。
开始结点用于存储链表的第一个数据元素。
2.何时选用顺序表、何时选用链表作为线性表的存储结构为宜?【答】顺序表中查找元素、获取表长非常容易,但是,要插入或者删除一个元素却需要移动大量的元素;相反,链表中却是方便插入或者删除元素,在查找元素的是,需要进行遍历。
因此,当所涉及的问题常常进行查找等操作,而插入、删除相对较少的是,适合采用顺序表;当常常需要插入、删除的时候,适合采用链表。
3.为什么在单循环链表中设置尾指针比设置头指针更好?【答】在单循环链表中,设置尾指针,可以更方便的判断链表是否为空。
4.在单链表、双链表和单循环链表中,若仅知道指针p指向某结点,不知道头指针,能否将结点*p从相应的链表中删去?【答】本题分三种情况讨论:1、单链表:当知道指针p指向某结点时,能够根据该指针找到其直接后继,但是不知道头指针,因此不能找到该结点的直接前趋,因此,无法删除该结点。
2、双链表:根据指针p可以找到该结点的直接前趋和直接后继,因此,能够删除该结点。
3、单循环链表:和双链表类似,根据指针p也可以找到该结点的直接前趋和直接后继,因此,也可以删除该结点。
5.下述算法的功能是什么?LinkList Demo(LinkList *L) /* L是无头结点单链表*/{LNode *Q,*P;if(L&&L->next){Q=L;L=L->next;P=L;while (P->next) P=P->next;P->next=Q; Q->next=NULL;}return L;} /* Demo */【答】将原来的第一个结点变成末尾结点,原来的第二个结点变成链表的第一个结点。
DS02_线性表04_其他链表

张 王 李 赵 吴
1 2 3 4 5 0 7 8 0
张 王 李 赵 吴
1 2 3 5 5 0 7 8 0
静态链表
在线性表(张 中删除" 在线性表 张,王,李,赵,吴)中删除"赵" 中删除
data next 0 1 2 3 4 5 6 7 8 data next 0 1 2 删除赵 归还空间 3 4 5 6 7 8
张 王 李 赵 吴
1 2 3 4 5 0 7 8 0
张 王 李 吴
1 2 3 5 6 0 7 8 0
静态链表
相对于顺序表而言,静态链表有什么优点? 相对于顺序表而言,静态链表有什么优点? 优点:在执行插入和删除操作时,只需修改游标, 优点:在执行插入和删除操作时,只需修改游标, 不需要移动表中的元素, 不需要移动表中的元素,从而改进了在顺序表中插 入和删除操作需要移动大量元素的缺点. 入和删除操作需要移动大量元素的缺点. 缺点: 缺点:没有解决连续存储分配带来的表长难以确定 的问题;静态链表还需要维护一个空闲链; 的问题;静态链表还需要维护一个空闲链;静态链 表不能随机存取. 表不能随机存取.
双链表的操作——删除 删除 双链表的操作
Status ListDelete(DuLinkList L,int i,ElemType &e) // 算法 算法2.19 { // 删除带头结点的双链循环线性表L的第 个元素,i的合法值为 删除带头结点的双链循环线性表 的第i个元素, 的合法值为1≤i≤ 的第 个元素 的合法值为 表长 DuLinkList p; if(i<1) // i值不合法 值不合法 return ERROR; p=GetElemP(L,i); // 在L中确定第 个元素的位置指针 中确定第i个元素的位置指针 中确定第 个元素的位置指针p if(!p) // p=NULL,即第 个元素不存在 即第i个元素不存在 即第 return ERROR; e=p->data; p->prior->next=p->next; p->next->prior=p->prior; free(p);p = NULL; return OK; }
单链表数据结构

插入
if (p != NULL && j == i-1) { // 找到第i个结点
s = (LinkList) malloc ( sizeof (LNode)); // 生成新结点
s->data = e;
// 数据域赋值
s->next = p->next; //新结点指针指向后一结点
p->next = s; return OK;
6、销毁
4.6 销毁操作
while(L) { p = L->next; free(L); L=p;
// p指向第一结点(头节点为“哑结点”) // 释放首结点 // L指向p
}
// 销毁完成后,L为空(NULL)
算法的时间复杂度为:O(ListLength(L))
判空 求表长
4.7 其它操作
if(L->next==NULL) return TRUE; // 空
5、清空
4.5 清空操作
while (L->next) { p = L->next; L->next = p->next; free(p);
// p指向当前结点 // 头结点指向当前结点的后结点 // 释放当前结点内存
}
// 清空完成后,仍保留头结点L
算法的时间复杂度为:O(ListLength(L))
点。
5.1.2 逆序建立单链表
①建立一个带头结点的空单链表;
②输入数据元素ai,建立新结点p, 并把p插入在头结点之后成为第一个 结点。
③重复执行②步,直到完成单链表的 建立。
a1
a2 a1
创建出来的链表 点顺序与插入操作
顺序相反。
线性表知识点总结

线性表知识点总结一、概述线性表是数据结构中的一种基本结构,它是一种线性的、有序的、可重复的数据结构。
线性表的存储结构有两种:顺序存储和链式存储。
二、顺序存储顺序存储的方式是把线性表的元素按照顺序存储在一个一维数组中,它的优点是随机访问时间复杂度为O(1),缺点是插入和删除操作时间复杂度为O(n)。
1. 初始化线性表的初始化需要先定义一个结构体,包含数据元素和线性表的长度两个成员。
```c#define MaxSize 100typedef struct{ElemType data[MaxSize];int length;}SqList;```2. 插入线性表的插入操作需要先判断是否有足够的空间进行插入操作,然后将插入位置后面的元素后移,最后将待插入的元素插入到插入位置。
```cStatus ListInsert(SqList &L, int i, ElemType e){int j;if(i<1 || i>L.length+1){return ERROR;}if(L.length>=MaxSize){return ERROR;}for(j=L.length;j>=i;j--){L.data[j]=L.data[j-1];}L.data[i-1]=e;L.length++;return OK;}```3. 删除线性表的删除操作需要先判断要删除的位置是否合法,然后将删除位置后面的元素前移,最后将最后一个元素赋值为空。
```cStatus ListDelete(SqList &L, int i, ElemType &e){int j;if(i<1 || i>L.length){return ERROR;}e=L.data[i-1];for(j=i;j<L.length;j++){L.data[j-1]=L.data[j];}L.length--;return OK;}```4. 查找线性表的按值查找操作需要遍历整个数组进行查找,时间复杂度为O(n),按位查找可以通过数组下标直接访问。
数据结构课件单链表
删除链表中的节点需要遍历至指定位置,时间复杂度为 O(n)。
查找节点
在链表中查找一个节点需要遍历整个链表,时间复杂度为 O(n)。
空间复杂度
空间占用
单链表的空间占用主要取决于链表中的 节点数,因此空间复杂度为O(n)。
VS
内存分配
每个节点需要分配内存空间存储数据和指 针,因此内存分配的空间复杂度也为O(n) 。
需要根据数据元素顺 序进行遍历的场景, 如排序算法等。
需要频繁插入、删除 操作的场景,如动态 规划、图算法等。
02
单链表的实现
创建单链表
定义节点结构体
首先需要定义一个节点结构体,包含 数据域和指针域两个部分,数据域用 于存储数据,指针域用于指向下一个 节点。
初始化头节点
创建一个头节点,并将其指针域指向 NULL,表示单链表的起始位置。
05
单链表常见问题与解决方 案
循环链表
总结词
循环链表是一种特殊类型的单链表,其中尾节点的指针指向头节点,形成一个闭环。
详细描述
在循环链表中,由于尾节点的指针指向头节点,因此遍历链表时需要特别注意,以避免无限循环。常见的解决方 法是在遍历时记录已经访问过的节点,避免重复访问。
链表中的重复元素
总结词
链表中可能存在重复元素的问题,这会影响数据处理的正确性。
详细描述
为了解决这个问题,可以在插入节点时检查新元素是否已存在于链表中。如果存在,则不进行插入操 作。另外,也可以使用哈希表等数据结构来快速查找重复元素。
链表的排序
总结词
对链表进行排序是常见的需求,但链表的排 序算法通常比数组的排序算法复杂。
合并单链表
总结词
将两个已排序的单链表合并为一个新的已排序的单链表。
线性表(单链表、循环链表-python实现)
线性表(单链表、循环链表-python实现)⼀、线性表 线性表的定义: 线性表是具有相同数据类型的有限数据的序列。
线性表的特点: 出了第⼀个元素外,每个元素有且仅有⼀个直接前驱,除最后⼀个元素外有且只有⼀个后继。
线性表是⼀种逻辑结构,表⽰元素之间的⼀⼀的相邻关系,顺序表和链表是指存储结构,两者属于不同的概念。
线性表的顺序表⽰: 线性表的顺序存储即数组的动态、静态分配,特点是可以随机访问。
线性表的链式表⽰: 线性表的链式存储即单链表、双连表、循环单链表以及循环双连表,特点是随机插⼊,不可随机访问。
单链表的实现(python):#定义每个节点class Node:def__init__(self,data):self.data=dataself.next=Noneclass linkList:#初始化头结点def__init__(self,n):self.head=Node(None)self.n=n#头插法建⽴链表def listCreateForward(self):if self.n==0:return Falseelse:temp=self.headfor i in range(1,self.n+1):print('请输⼊第{0}个节点:'.format(i))num = input()node = Node(num)node.next=temp.nexttemp.next = node#尾插法建⽴链表def listCreateBackward(self):if self.n==0:return Falseelse:temp=self.headfor i in range(1,self.n+1):print('请输⼊第{0}个节点:'.format(i))num = input()node = Node(num)temp.next=nodetemp=node#读取链表def readList(self):if self.n==0:print("空链表!")else:temp = self.headwhile temp.next!=None:temp = temp.nextprint(temp.data,end='')#链表长度def Length(self):i=0temp=self.headwhile temp.next!=None:temp=temp.nexti+=1return i#按值查找def locateElem(self,num):i = 0temp = self.headwhile temp.next != None:temp = temp.nexti += 1if int(temp.data)==num:return ireturn None#按位置查找def getElem(self,j):i = 0temp = self.headwhile temp.next != None:temp = temp.nexti += 1if int(j)==i:return temp.datareturn None#按位置插⼊数字def listInsert(self,j,num):if int(j)<0:return Noneelif self.Length()<j:return Noneelse:i = 0temp = self.headwhile temp.next != None:i += 1if int(j) == i:node=Node(num)node.next=temp.nexttemp.next=nodetemp = temp.next#删除特定元素def deleteData(self,num):temp=self.headwhile True:if temp.next==None:break#当这个节点是尾节点时if int(temp.next.data)==num and temp.next.next==None: temp.next=Nonebreakelif int(temp.next.data)==num:temp.next=temp.next.nexttemp=temp.next#删除特定位置的元素def deleteElem(self,j):if j==1:self.head.next=self.head.next.nextelif j==self.Length() :temp=self.head.nextwhile True:if temp.next.next==None:temp.next=Nonebreaktemp=temp.nextelif j<self.Length():i=2temp=self.head.nextwhile True:if i==j:temp.next=temp.next.nextelse:print('erro')return Nonelinklist1=linkList(5)linklist1.listCreateBackward()linklist1.readList()length=linklist1.Length()print('length={0}'.format(length))locate=linklist1.locateElem(5)print('5在位置{0}'.format(locate))data=linklist1.getElem(3)print('第3个位置是{0}'.format(data))linklist1.listInsert(1,111)linklist1.readList()print('\n删除111(第⼀个元素):')linklist1.deleteData(111)linklist1.readList()print('\n删除5(末尾的元素)')linklist1.deleteData(5)linklist1.readList()print('\n删除第⼀个元素:')linklist1.deleteElem(1)linklist1.readList()print('\n删除末尾的元素')linklist1.deleteElem(3)linklist1.readList()结果:请输⼊第1个节点:1请输⼊第2个节点:2请输⼊第3个节点:3请输⼊第4个节点:4请输⼊第5个节点:51 2 3 4 5 length=55在位置5第3个位置是3111 1 2 3 4 5删除111(第⼀个元素):1 2 3 4 5删除5(末尾的元素)1 2 3 4删除第⼀个元素:2 3 4删除末尾的元素2 3 循环链表的实现(python):其它部分与单链表相似#定义节点class Node:def__init__(self,data):self.data=dataself.next=Noneclass circleList:# 初始化头结点def__init__(self,n):self.head=Node(None)self.head.next=self.headself.n = n# 头插法建⽴链表-def listCreateForward(self):if self.n==0:return Falseelse:temp=self.headfor i in range(1,self.n+1):print('请输⼊第{0}个节点:'.format(i))num = input()node = Node(num)node.next=temp.nexttemp.next = node temp=temp.next# 尾插法建⽴链表def listCreateBackward(self):if self.n==0:return Falseelse:temp=self.headfor i in range(1,self.n+1):print('请输⼊第{0}个节点:'.format(i))num = input()node = Node(num)temp.next=nodetemp=nodetemp.next = self.head#读取循环链表def readList(self):if self.n==0:print("空链表!")else:temp = self.headwhile temp.next!=self.head: temp = temp.nextprint(temp.data,end='') linklist1=circleList(5)linklist1.listCreateForward()linklist1.readList()linklist1=circleList(5)linklist1.listCreateBackward() linklist1.readList()。
DS第二章_课后习题答案
第二章线性表2.1 填空题<1>一半插入或删除的位置<2>静态动态<3>一定不一定<4>头指针头结点的next 前一个元素的next2.2 选择题<1>A <2> DA GKHDA EL IAF IFA<IDA><3>D <4>D <5> D2.3头指针:在带头结点的链表中,头指针存储头结点的地址;在不带头结点的链表中,头指针存放第一个元素结点的地址;头结点:为了操作方便,在第一个元素结点前申请一个结点,其指针域存放第一个元素结点的地址,数据域可以什么都不放;首元素结点:第一个元素的结点。
2.4已知顺序表L递增有序,写一算法,将X插入到线性表的适当位置上,以保持线性表的有序性。
void InserList<SeqList *L,ElemType x>{int i=L->last;if<L->last>=MAXSIZE-1> return FALSE; //顺序表已满while<i>=0 && L->elem[i]>x>{L->elem[i+1]=L->elem[i];i--;}L->elem[i+1]=x;L->last++;}2.5 删除顺序表中从i开始的k个元素int DelList<SeqList *L,int i,int k>{int j,l;if<i<=0||i>L->last> {printf<"The Initial Position is Error!">; return 0;}if<k<=0> return 1; /*No Need to Delete*/if<i+k-2>=L->last> L->last=L->last-k; /*modify the length*/for<j=i-1,l=i+k-1;l<L->last;j++,l++>L->elem[j]=L->elem[l];L->last=L->last-k;return 1;}2.6 已知长度为n的线性表A采用顺序存储结构,请写一时间复杂度为O<n>、空间复杂度为O<1>的算法,删除线性表中所有值为item的数据元素。
DS02_线性表_常见问题
a=a-b;
作业
2.22 试写一算法,对单链表实现就地逆置。
p:指向已逆序链的第一个结点 q:指向待插入链的第一个结点 s:指向待插入链的第二个结点
问题:ADT
什么是抽象数据类型ADT? 抽象数据类型(Abstract Data Type,ADT):一个数学 模型以及定义在该模型上的一组操作的总称。 例P19 ADT线性表的定义 抽象数据类型是与表示无关的数据类型 抽象数据类型的设计者根据这些描述给出操作的具体实 现,抽象数据类型的使用者依据这些描述使用抽象数据 类型。 关键:使用它的人可以只关心它的逻辑特征,不需要了 解它的存储方式。
问题:ElemType
《实验一》中typedef int ElemType; ElemType是什么? 结点(也就是数据元素)类型
线性表:是n(n≥0)个具有相同类型的数据元素的有限序列。每个数据 元素表(A,B,C,……,Z) 数字,如 记录等
如果没有ElemType, P22顺序表的存储结构该如何定义?基本操作该如 何实现? 所有出现ElemType的地方都换成int?char?other else? 有了ElemType之后,对于某个特定应用我们只需typedef int ElemType; 或typedef char ElemType; 那么,现在我们可以理解为什么《实验一》中typedef int ElemType;
例p19adt线性表的定义抽象数据类型的设计者根据这些描述给出操作的具体实现抽象数据类型的使用者依据这些描述使用抽象数据类型
问题:for 语句的执行顺序
for语句的执行顺序 for语句格式为: for(表达式1;表达式2;表达式3) 语句:/*循环体*/ 该语句执行过程如下: 表达式1 (表达式2、循环体、表达式3)、 (表达式2、循环体、表达式 3)、 (表达式2、循环体、表达式3)、 (表达式2、循环体、表 达式3)…… 如 for (int a=0,i=0; i<10; ++i) { a+=i;}