数据结构 2线性表的单链表存储结构
数据结构习题及答案与实验指导(线性表)2
第2章线性表线性表是一种最基本、最常用的数据结构,它有两种存储结构——顺序表和链表。
本章主要介绍线性表的定义、表示和基本运算的实现。
重点讨论了线性表的存储结构,以及在顺序、链式两种存储结构上基本运算的实现。
重点提示:●线性表的逻辑结构特征●线性表的顺序存储和链式存储两种存储结构的特点●在两种存储结构下基本操作的实现2-1 重点难点指导2-1-1 相关术语1.线性表线性表是具有相同数据类型的n(n≥0)个数据元素的有限序列,通常记为:(a1,a2,…,a n),其中n为表长,n=0时称为空表。
要点:一种逻辑结构,其数据元素属于相同数据类型,之间的关系是线性关系。
2.顺序表顺序存储的线性表。
要点:按线性表中的元素的逻辑顺序依次存放在地址连续的存储单元里,其存储特点:用物理上的相邻实现逻辑上的相邻。
3.链表用链表存储的线性表。
要点:链表是通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的,对每个结点的地址是否连续没有要求。
4.单链表每个结点除了数据域外还有一个指向其后继的指针域。
要点:通常将每个元素的值和其直接后继的地址作为一个结点,通过每个结点中指向后继结点的指针表示线性表的逻辑结构。
5.头指针要点:头指针是一个指针变量,里面存放的是链表中首结点的地址,并以此来标识一个链表。
如链表H,链表L等,表示链表中第一个结点的地址存放在指针变量H、L中。
通常用头指针来惟一标识一个链表。
6.头结点要点:附加在第一个元素结点之前的一个结点,头指针指向头结点。
当该链表表示一个非空的线性表时,头结点的指针域指向第一个元素结点;为空表时,该指针域为空。
7.头结点的作用要点:其作用有两个,一是使对空表和非空表的处理得到统一;二是在链表的第一个位置上的操作和在其他位置上的操作一致,无需特殊处理。
2-1-2 线性表的顺序存储1.顺序表顺序存储的线性表称为顺序表。
其特点是:用一组地址连续的存储单元来依次存放线性表的数据元素,因此数据元素的逻辑顺序和物理次序一致(这是顺序存储的核心所在)。
数据结构 线性表
第1讲线性表本章主要掌握如下内容:线性表的定义和基本操作,线性表的实现,线性表的顺序存储结构及链式存储结构,线性表的应用。
知识点分析(一)线性表的定义和基本操作1.线性表基本概念1)定义:是由相同类型的结点组成的有限序列。
如:由n个结点组成的线性表(a1, a2, …, a n)a1是最前结点,a n是最后结点。
结点也称为数据元素或者记录。
2)线性表的长度:线性表中结点的个数称为其长度。
长度为0的线性表称为空表。
3)结点之间的关系:设线性表记为(a1,a2,…a i-1 , a i, a i+1 ,…a n),称a i-1是a i的直接前驱结点....(简称前驱),a i+1是a i的直接后继结点....(简称后继)。
4)线性表的性质:①线性表结点间的相对位置是固定..的,结点间的关系由结点在表中的位置确定。
②如果两个线性表有相同的数据结点,但它们的结点顺序不一致,该两个线性表也是不相等的。
注意:线性表中结点的类型可以是任何数据(包括简单类型和复杂类型),即结点可以有多个成分,其中能唯一标识表元的成分称为关键字(key),或简称键。
以后的讨论都只考虑键,而忽略其它成分,这样有利于把握主要问题,便于理解。
『经典例题解析』线性表的特点是每个元素都有一个前驱和一个后继。
( )【答案】错误。
【解析】线性表的第一个数据元素没有前驱,最后一个元素没有后继。
其余的所有元素都有一个前驱和后继。
2.线性表的抽象数据类型线性表是一个相当灵活的数据结构,其长度可以根据需要增加或减少。
从操作上讲,用户不仅可以对线性表的数据元素进行访问操作,还可以进行插入、删除、定位等操作。
1)线性表的基本操作假设线性表L有数据对象 D={ai | ai∈ElemSet,i=1,2,3,…,n,n>=0},数据元素之间的关系R={<ai-1,ai>|ai-1,ai∈D,i=1,2,…,n},则线性表L的基本操作如下所示:●InitList(&L):其作用是构造一个长度为0的线性表(空线性表);●DestoryList(&L):其作用是销毁当前的线性表L;●ClearList(&L):清空线性表L,使之成为空表;●ListLength(L):返回线性表L的长度,即线性表中数据元素的个数;●ListEmpty(L) :判断线性表L是否为空表,是则返回True,否则返回False;●GetElem(L,i,&e):将线性表L中第i个数据元素的值返回到变量e中;●LocateELem(L,e,compare( )) :判断线性表L中是否存在与e满足compare()条件的数据元素,有则返回第一个数据元素;●PriorElem(L,cur_e,&pri_e):返回线性表L中数据元素cur_e的前驱结点;●NextElem(L,cur_e,&next_e):返回线性表L中数据元素cur_e的后继结点;●ListInsert(&L,i,e):向线性表L的第i个位置之前插入一个数据元素,其值为e;●ListDelete(&L,i,&e):删除线性表L的第i个数据元素,并将该数据元素的值返回到e中;●ListTraverse(L,visit()):遍历线性表中的每个数据元素。
(完整word版)数据结构单元2练习参考答案
单元练习2一.判断题(下列各题,正确的请在前面的括号内打√;错误的打╳)(×)(1)线性表的链式存储结构优于顺序存储。
(×)(2)链表的每个结点都恰好包含一个指针域。
(√)(3)在线性表的链式存储结构中,逻辑上相邻的两个元素在物理位置上并不一定紧邻。
(×)(4)顺序存储方式的优点是存储密度大,插入、删除效率高。
(×)(5)线性链表的删除算法简单,因为当删除链中某个结点后,计算机会自动地将后续的各个单元向前移动。
(×)(6)顺序表的每个结点只能是一个简单类型,而链表的每个结点可以是一个复杂类型。
(√)(7)线性表链式存储的特点是可以用一组任意的存储单元存储表中的数据元素。
(√)(8)线性表采用顺序存储,必须占用一片连续的存储单元。
(×)(9)顺序表结构适宜于进行顺序存取,而链表适宜于进行随机存取。
(ㄨ)(10)插入和删除操作是数据结构中最基本的两种操作,所以这两种操作在数组中也经常使用。
二.填空题(1)顺序表中逻辑上相邻的元素在物理位置上必须相连。
(2)线性表中结点的集合是有限的,结点间的关系是一对一关系。
(3)顺序表相对于链表的优点是:节省存储和随机存取。
(4)链表相对于顺序表的优点是:插入、删除方便。
(5)采用顺序存储结构的线性表叫顺序表。
(6)顺序表中访问任意一个结点的时间复杂度均为O(1)。
(7)链表相对于顺序表的优点是插入、删除方便;缺点是存储密度小。
(8)在双链表中要删除已知结点*P,其时间复杂度为O(1)。
(9)在单链表中要在已知结点*P之前插入一个新结点,需找到*P的直接前趋结点的地址,其查找的时间复杂度为 O(n) 。
(10)单链表中需知道头指针才能遍历整个链表。
(11)线性表中第一个结点没有直接前趋,称为开始结点。
(12)在一个长度为n的顺序表中删除第i个元素,要移动n-i 个元素。
(13)在一个长度为n的顺序表中,如果要在第i个元素前插入一个元素,要后移n- i +1 个元素。
数据结构第二章:线性表
实现:可用C 实现:可用C语言的一维数组实现
6
V数组下标 0 1
内存 a1 a2
元素序号 1 2
typedef int DATATYPE; #define M 1000 DATATYPE data[M]; 例 typedef struct card { int num; char name[20]; char author[10]; char publisher[30]; float price; }DATATYPE; DATATYPE library[M];
4
{加工型操作 加工型操作} 加工型操作
ClearList( &L ) 初始条件:线性表 L 已存在。 操作结果:将 L 重置为空表。 PutElem( &L, i, &e ) 初始条件:线性表L已存在,1≤i≤LengthList(L)。 操作结果:L 中第 i 个元素赋值同 e 的值 ListInsert( &L, i, e ) 初始条件:线性表 L 已存在,1≤i≤LengthList(L)+1。 操作结果:在 L 的第 i 个元素之前插入新的元素 e,L 的长度增1。 ListDelete( &L, i, &e ) 初始条件:线性表 L 已存在且非空,1≤i≤LengthList(L)。 操作结果:删除 L 的第 i 个元素,并用 e 返回其值,L 的长度减1。 }ADT LIST
3
PriorElem( PriorElem L, cur_e, &pre_e ) 初始条件:线性表 L 已存在。 操作结果:若 cur_e 是 L 中的数据元素,则用 pre_e 返回 它的前驱,否则操作失败,pre_e 无定义。 NextElem( NextElem L, cur_e, &next_e ) 初始条件:线性表 L 已存在。 操作结果:若 cur_e 是 L 中的数据元素,则用 next_e 返 回它的后继,否则操作失败,next_e 无定义。 GetElem( GetElem L, i, &e ) 初始条件:线性表 L 已存在,1≤i≤LengthList(L)。 操作结果:用 e 返回 L 中第 i 个元素的值。 LocateElem( LocateElem L, e, compare( ) ) 初始条件:线性表 L 已存在,compare( ) 是元素判定函数。 操作结果:返回 L 中第1个与 e 满足关系 compare( ) 的元 素的位序。若这样的元素不存在,则返回值为0。 ListTraverse(L, visit( )) ListTraverse 初始条件:线性表 L 已存在,visit( ) 为元素的访问函数。 操作结果:依次对 L 的每个元素调用函数 visit( )。 一旦 visit( ) 失败,则操作失败。
数据结构课件第2章线性表
27
线性表的顺序存储结构适用于数据 元素不经常变动或只需在顺序存取设备 上做成批处理的场合。为了克服线性表 顺序存储结构的缺点,可采用线性表的 链式存储结构。
28
2.3 线性表的链式存储结构
线性表的链式存储表示 基本操作在单链表上的实现 循环链表 双向链表 线性表链式存储结构小结
2.3.1 线性表的链式存储表示 29
2.1.1 线性表的定义
6
一个线性表(linear_list)是 n(n≥0)个具有相同属性的数 据元素的有限序列,其中各元素有着依次相邻的逻辑关系。
线性表中数据元素的个数 n 称为线性表的长度。当 n = 0 时 该线性表称为空表。当 n > 0 时该线性表可以记为:
(a1,a2,a3,…,ai,…,an)
数据域 指针域
结点 data next
31
(2) 线性表的单链表存储结构
通过每个结点的指针域将线性表中 n 个结点按其逻辑顺序链 接在一起的结点序列称为链表,即为线性表 ( a1, a2, a3, …, ai, …, an ) 的链式存储结构。如果线性链表中的每个结点只有一个指针域, 则链表又称为线性链表或单链表 (linked list)。
17
(2) 算法编写
#define OK 1
#define ERROR 0
Int InsList ( SeqList *L, int i, ElemType e ) /*在顺序线性表 L 中第 i 个位置插入新的元素 e。*/ /* i 的合法值为 1≤i ≤L->last+2*/ {
int k; if ( i < 1) ||( i > L->last+2)) /*首先判断插入位置是否合法*/ { printf(“插入位置i值不合法”);
《数据结构》课程课件第二章线性表
Step2:数据域赋值
插入后: Step3:插入(连接)
X q
(1)式和(2)式的顺序颠倒,可以吗?
4、插入元素(在第i个元素之前插入元素e)
为什么时间复杂度不再是O(1)?
第i-1个元素
第i个元素
p
s
新插入元素
5、删除p所指元素的后继元素
P
删除前:
P->next P->next->next
删除:
五、线性表ADT的应用举例
Void mergelist(list La,list Lb,list &Lc)
{ //已知线性表La和Lb中的数据元素按值非递减排列
//归并La和Lb得到新的线性表Lc,Lc中的元素也按值非递减排列
例: 将两个各有n个元素的有序表归并成一个有序表, 其最小的比较次数是( )。 A、n B、2n-1 C、2n D、n-1
三、线性表的ADT
四、线性表的分类
五、线性表ADT的应用举例
例1:已知有线性表L,要求删除所有X的出现
五、线性表ADT的应用举例
例2: 已知有两个分别有序的线性表(从小到大),要 求合并两个线性表,且合并后仍然有序。——归并 方法1: 合并,再排序O((m+n)2)
方法2: 归并,利用分别有序的特点O((m+n))
二、线性表上常见的运算
8、删除 Delete(L,i):删除线性表的第i个元素 删除前 a1 a2 … ai-1 ai ai+1 … an 删除后 a1 a2 … ai-1 ai+1 … an 9、判断是否为空 Empty(L):线性表空,则返回TRUE, 否则FALSE 10、输出线性表 Print(L):输出线性表的各个元素 11、其它操作 复制、分解、合并、分类等
数据结构C语言版 线性表的单链表存储结构表示和实现
#include 〈stdio.h>#include <malloc。
h>#include 〈stdlib.h>/*数据结构C语言版线性表的单链表存储结构表示和实现P28—31编译环境:Dev-C++ 4。
9。
9。
2日期:2011年2月10日*/typedef int ElemType;// 线性表的单链表存储结构typedef struct LNode{ElemType data; //数据域struct LNode *next;//指针域}LNode, *LinkList;// typedef struct LNode *LinkList;// 另一种定义LinkList的方法// 构造一个空的线性表Lint InitList(LinkList *L){/*产生头结点L,并使L指向此头结点,头节点的数据域为空,不放数据的。
void *malloc(size_t)这里对返回值进行强制类型转换了,返回值是指向空类型的指针类型.*/(*L)= (LinkList)malloc(sizeof(struct LNode) );if( !(*L))exit(0);// 存储分配失败(*L)-〉next = NULL;// 指针域为空return 1;}// 销毁线性表L,将包括头结点在内的所有元素释放其存储空间。
int DestroyList(LinkList *L){LinkList q;// 由于单链表的每一个元素是单独分配的,所以要一个一个的进行释放while(*L ){q = (*L)—〉next;free(*L );//释放*L = q;}return 1;}/*将L重置为空表,即将链表中除头结点外的所有元素释放其存储空间,但是将头结点指针域置空,这和销毁有区别哦。
不改变L,所以不需要用指针。
*/int ClearList( LinkList L ){LinkList p,q;p = L—〉next;// p指向第一个结点while( p ) // 没到表尾则继续循环{q = p—>next;free( p );//释放空间p = q;}L—>next = NULL; // 头结点指针域为空,链表成了一个空表return 1;}// 若L为空表(根据头结点L—〉next来判断,为空则是空表),则返回1,// 否则返回0.int ListEmpty(LinkList L){if(L—>next ) // 非空return 0;elsereturn 1;}// 返回L中数据元素个数。
数据结构(二):线性表的链式存储结构
数据结构(⼆):线性表的链式存储结构1、为什么要使⽤链式存储结构?因为我们前⾯讲的线性表的顺序存储结构,他是有缺点的。
最⼤的缺点就是插⼊和删除时需要移动⼤量元素,这显然就需要耗费时间。
要解决这个问题,我们就需要分析⼀下为什么当插⼊和删除时,就要移动⼤量元素,因为相邻两元素的存储位置也具有相邻关系,它们在内存中的位置也是挨着的,中间没有空隙,当然就⽆法快速介⼊,⽽删除之后。
当中就会留出空隙,⾃然就需要弥补。
问题就出在这⾥。
为了解决这个问题,⾃然⽽然的就出现了链式存储结构。
2、线性表链式存储结构的特点:线性表的链式存储结构不考虑元素的存储位置,⽽是⽤⼀组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的,这就意味着,这些数据元素可以存在内存未被占⽤的任意位置。
顺序存储结构:只需要存储数据元素信息。
链式存储结构:除了要存储数据元素信息之外,还要存储⼀个指⽰其直接后继元素的存储地址。
3、关键词:数据域:存储数据元素信息的域。
指针域:存储直接后继位置的域。
指针或链:指针域中存储的信息。
结点(Node):指针域+数据域组成数据元素的存储映像。
头指针:链表中第⼀个结点的存储位置。
头节点:在单链表的第⼀个结点前附设⼀个结点,成为头结点。
头结点的数据域不可以存储任何信息,可以存储线性表的长度等附加信息,头结点的指针域存储指向第⼀个结点的指针。
4、单链表:定义:n个结点链成⼀个链表,即为线性表的链式存储结构,因此此链表的每个结点中只包含⼀个指针域,所以叫做单链表。
PS:线性链表的最后⼀个结点指针为“空”,通常⽤NILL或“^”符号表⽰。
头节点:在单链表的第⼀个结点前附设⼀个结点,成为头结点。
头结点的数据域不可以存储任何信息,可以存储线性表的长度等附加信息,头结点的指针域存储指向第⼀个结点的指针。
5、头结点与头指针的异同(1)头结点头结点是为了操作的统⼀和⽅便⽽设⽴的,放在第⼀个元素的结点之前,其数据域⼀般⽆意义(也可存放链表的长度)有了头结点,对第⼀元素结点前插⼊和删除第⼀结点,其操作就统⼀了头结点不⼀定是链表的必要素(2)头指针头指针式指向第⼀个结点的指针,若链表有头结点,则是指向头结点的指针。
线性表的链式存储结构
线性表的链式存储结构
线性表的链式存储结构是指用一组任意的存储单 元(可以连续,也可以不连续)存储线性表中的数据 元素。为了反映数据元素之间的逻辑关系,对于每个 数据元素不仅要表示它的具体内容,还要附加一个表 示它的直接后继元素存储位置的信息。假设有一个线 性表(a,b,c,d),可用下图2所示的形式存储:
27
p
s
图 2-9
28
完整的算法:
int DuListInsert(DuLinkList *L,int i,EntryType e)
if (L.head->next==NULL) return TRUE; else return FALSE; }
12
6. 通过e返回链表L中第i个数据元素的内容 void GetElem(LinkList L,int i,EntryType *e) {
LNode *p; int j; //j为计数器,记载所经过的结点数目 if (i<1||i>ListLength(L)) exit ERROR; //检测i值的合理性 for (p=L.head,j=0; j!=i;p=p->next,j++); //找到第i个结点 *e=p->data; //将第i个结点的内容赋给e指针所指向的存储单元中 }
10
4. 求链表L的长度
int ListLength(LinkList L)
{
LNode *p;
int len;
for(p=L.head, len=0;p->next==NULL; p=p->next,len++);
return(len);
循环条件表达式 重复执行的语句
数据结构 第2章 线性表
123456
1 3
2 5
4
6
8
整理ppt
06/03/2021
线性表链式结构的存储示意
假设我们有一个线性表(a1,a2,…,an)
数据信息
结点
指针
……
ai 0500
数据域 指针域
图a:链表中的相邻元素
……
ai+1 0800
地址0500
头指针
第一个结点
12
整理ppt
06/03/2021
实现读取单链表第i个元素的代码
/* 初始条件:链式线性表L已存在,0 < i < ListLength(L)+1 */ /* 操作结果:用 e 返回 L 中第 i 个数据元素的值 */
1. Status GetElem (LinkList L, int i, ElemType *e)
2. { /* 参数 L 是待操作的链表,其实也是头结点 */
3.
int j;
4.
Node *p;
/* 声明一结点指针p */
5.
p = L->next;
/* 让p指向链表L的第一个结点 */
6.
j = 1;
/* j为计数器 */
7.
while (p && j<i) /* p不为空或者计数器j还没有等于i时,循环继续 */
8.
{
9.
p = p->next; /* 让p指向下一个结点 */
10.
++j;
11.
}
12. if (!p || j>i)
13.
2-4-数据结构——从概念到C++实现(第3版)-王红梅-清华大学出版社
华
…
大 学
空表 first = NULL
出
0325 a3
版 社
非空表 first a1
a2
an ∧
0300 …
单链表的存储方法
头指针:指向第一个结点的存储地址
尾标志:终端结点的指针域为空
数 据
结
构
头结点:在第一个元素结点之前附设一个类型相同的结点
( 从 概
现
)
清
华
大
学
空表 first
∧
出 版 社
非空表 first
a1
a2
an ∧
单链表的结点结构定义
template <typename DataType> struct Node {
DataType data; struct Node *next; } Node;
first
a1
a2
数 据 结 构 ( 从 概 念 到 实 现 ) 清 华 大 学 出 版 社
单链表的实现——遍历
first
first
a1
a2
an ∧
数
据
结
构
first 指向头结点 first修改前:(a1, a2, … , an)
( 从 概 念 到
first修改后:(a2, … , an)
实 现 )
清
华
大
为什么设置工作指针?通过头指针后移扫描单链表会有什么后果?
学 出 版
社
单链表头指针的作用是标识单链表的开始,通常不修改头指针
单链表的实现——初始化
初始化一个单链表要完成哪些工作呢?
first
∧
数
据
template <typename DataType>
数据结构复习题2
一、填空题1.数据结构包括、和三方面的内容。
2.数据的逻辑结构分为、、、。
3.数据的逻辑结构分为和两大类。
4.数据的存储结构被分为、、、。
5.数据的存储方式有、、和四种基本存储方式。
6.顺序存储和链式存储相比较的存储密度大,的插入删除方便。
7.在线性表的单链接存储结构中,每个结点包含有两个域,一个叫域,另一个叫域。
8.在线性表的单链接存储中,若一个元素所在结点的地址为P,则其后继结点的地址为,若假定P为一个数组a中的下标,则其后继结点的下标为。
9.在顺序存储的向量中,设第一个元素的地址为loc(k1),每个元素占用的空间为M,则第i个元素ki的地址为loc(ki)=loc(k1)+(i-1)*M 。
10.在循环单链表中,最后一个结点的指针域指向结点。
11.队列的插入操作在进行,删除操作在进行。
12.一棵n个结点的树,其边数为条。
13.设二叉树根结点的层数为0,则第i层上最多有个结点。
14.在一棵二叉树中,第5层上的结点数最多为。
15.深度为 K 的完全二叉树,至少有个结点,至多有个结点。
16.深度为 8 (根的层次号为 1 )的满二叉树有个叶子结点。
17.深度为K的二叉树结点总数最大为。
18.深度为 k (根的层次号为 1 )的满二叉树有个叶子结点。
19.在完全二叉树中,对结点按层次编号,根结点编号为1。
若结点i有右子女,则右子女的编号为,左子女的编号为。
20.按后根次序周游树林,正好等同于按次序周游与之对应的二叉树。
21.按先根次序周游树林,正好等同于按次序周游对应的二叉树。
22.对一棵二叉排序树进行中序遍历时,得到的结点序列是一个。
23.在一个具有n个顶点的无向完全图中,包含有条边。
24.设有m个结点的无向图中,如果其边数为就称为完全图。
25.在图中,与结点相关的边的数目称为该结点的。
26.在有向图的邻接表和逆邻接表表示中,每个顶点邻接表分别链接着该顶点的所有和结点。
27.对于一个长度为n的顺序存储的线性表,在表头插入元素的时间复杂度为,在表尾插入元素的时间复杂度为。
数据结构教学课件:线性表链表
头结点好处
a、由于开始结点的位置被存放在头结点的指针域中, 所以在链表的第一个位置上的操作(如插入、删 除等)就和在表的其它位置上的操作一致,无需 进行特殊处理; b、无论链表是否为空,其头指针是指向头结点的非 空指针(空表中头结点的指针域为空),头指针 始终不为空,因此空表和非空表的处理也就统一 了
}
带头结点的单链表 H
# a1 a2
…
an NULL
头结点
H
# NULL
头结点
linklist * initList() linklist * initList() { { linknode* pHead = (linknode*) linknode* pHead = 0; // pHead、 malloc( sizeof(linknode)); pRail分别为头、尾指针 linknode* pRail = pHead; linknode* pRail = pHead; // pHead、 char c; pRail分别为头、尾指针 char c; while( (c = getchar()) != ‘\n’) { linknode* pNode = while( (c = getchar()) != ‘\n’) { (linknode*)malloc( sizeof(linknod linknode* pNode = e )); (linknode*)malloc( sizeof( linknode scanf( "%c", &pNode->data ); )); scanf( "%c", &pNode->data ); pNode->next = 0; //新结点指 针域为空 pNode->next = 0; //新结点指针 pRail->next = pNode; 域为空 pRail = node; if( !pHead) pHead = pNode; } else pRail->next = pNode; return pHead; pRail = node; } } return pHead; }
数据结构第二章习题(2)
1.数据在计算机存储器内表示时,物理地址与逻辑地址相同并且是连续的,称之为:
(A)存储结构 (B)逻辑结构 (C)顺序存储结构 (D)链式存储结构
2.一个向量第一个元素的存储地址是 100,每个元素的长度为 2,则第 5 个元素的地址是
(A)110 (B)108
(C)100
(D)120
3.在 n 个结点的顺序表中,算法的时间复杂度是 O(1)的操作是: (A)访问第 i 个结点(1≤i≤n)和求第 i 个结点的直接前驱(2≤i≤n) (B)在第 i 个结点后插入一个新结点(1≤i≤n) (C)删除第 i 个结点(1≤i≤n) (D)将 n 个结点从小到大排序
五、线性表具有两种存储方式,即顺序方式和链接方式。现有一个具有五个元素的线性表
L={23,17,47,05,31},若它以链接方式存储在下列 100~119 号地址空间中,每个结点
由数据(占 2 个字节)和指针(占 2 个字节)组成,如下所示:
05 U 17 X 23 V 31 Y 47 Z
^
^
100
情况下适用于使用链式结构实现。
(A)需经常修改L中的结点值
(B)需不断对L进行删除插入
(C)L中含有大量的结点
(D)L中结点结构复杂
9.单链表的存储密度
(A)大于 1; (B)等于 1; (C)小于 1; (D)不能确定
10.设 a1、a2、a3 为 3 个结点,整数 P0,3,4 代表地址,则如下的链式存储结构称为
。
二、判断题
( )1. 链表的每个结点中都恰好包含一个指针。
( )2. 链表的物理存储结构具有同链表一样的顺序。
( )3. 链表的删除算法很简单,因为当删除链中某个结点后,计算机会自动地将后续的
数据结构课后练习 - 第2章
的联系,所以可以从头结点开始查找任何一个元素。 (×) 4. 顺序存储的线性表可以实现随机存取。(√ )
二、单项选择题
1. 用单链表方式存储的线性表,存储每个结点需要两个域, 一个数据域,另一个是______B。
A. 当前结点所在的地址域
B. 指针域
C. 空指针域
D. 空闲域
2. 在具有n个结点的单链表中,实现__A____的操作,其算法 的时间复杂度都是O(n)。
A. 遍历链表和求链表的第i个结点
B. 在地址为p的结点之后插入一个结点
C. 删除开始结点
D. 删除地址为p的结点的后继结点
二、单项选择题
3. 已知一个顺序存储的线性表,设每个结点需占m个存储单元,若第一
学习要点
3. 熟练掌握在顺序存储结构上线性表的基本操作,如查 找、插入和删除的算法。
4. 熟练掌握在各种链表结构中线性表的基本操作,能在 实际应用中选用适当的链表结构。
5. 能够从时间与空间复杂度方面综合比较线性表两种存 储结构的不同特点及其适用场合。
一、判断对错题
1. 线性表中的元素可以是各种各样的,但同一线性表中 的数据元素具有相同的特性,因此属于同一数据对象。 ( )√
• 插入结点:移动元素次数n-i+1; • 删除结点:移动元素次数n-i。 • 决定因素:顺序表的长度以及插入、删除元素在表中
的位序。
4. 分析下述三个算法的具体功能。
ListNode *Demo1(LinkList L, ListNode *p)
{ //L是有头结点的单链表
ListNode *q=L->next;
数据结构实验报告-单链表
2016级数据结构实验报告实验名称:实验一线性表——题目1学生姓名:李文超班级:2015661131班内序号:15学号:2015522147日期:2016年11月13日1.实验要求实验目的:根据线性表的抽象数据类型的定义,选择下面任一种链式结构实现线性表,并完成线性表的基本功能。
线性表存储结构(五选一):1、带头结点的单链表2、不带头结点的单链表3、循环链表4、双链表5、静态链表线性表的基本功能:1、构造:使用头插法、尾插法两种方法2、插入:要求建立的链表按照关键字从小到大有序3、删除4、查找5、获取链表长度6、销毁7、其他:可自行定义编写测试main()函数测试线性表的正确性。
2.程序分析2.1 存储结构单链表的存储:(1)链表用一组任意的存储单元来存放线性表的结点。
这组存储单元既可以是连续的,也可以是不连续的,甚至零散地分布在内存的某些位置。
(2)链表中结点的逻辑次序和物理次序不一定相同。
为了能正确表示结点间的逻辑关系,在存储每个元素值的同时,还要存储该元素的直接后继元素的位置信息,这个信息称为指针或链。
结点结构┌──┬──┐ data 域---存放结点值的数据域│data │next │ next 域---存放结点的直接后继的地址的指针域└──┴──┘单链表在内存中的存储示意地址 内存单元1000H头指针 1020H1080H10C0H2.2 关键算法分析1、关键算法:(1)头插法自然语言描述:a:在堆中建立新结点b:将a[i]写入到新结点的数据域c:修改新结点的指针域d:修改头结点的指针域。
将新结点加入链表中伪代码描述a:Node <T> * s=new Node <T>b:s->data=a[i]c:s->next=front->next;d:front->next=s(2)尾插法自然语言描述:a:在堆中建立新结点:b:将a[i]写入到新结点的数据域:c:将新结点加入到链表中d:修改修改尾指针伪代码描述a:Node <T> * s=new Node <T>b:s->data=a[i]c:r->next=s;d:r=s(3)遍历打印函数自然语言描述:a:判断该链表是否为空链表,如果是,报错b:如果不是空链表,新建立一个temp指针c:将temp指针指向头结点d:打印temp指针的data域e:逐个往后移动temp指针,直到temp指针的指向的指针的next域为空伪代码描述a: If front->next==NULL①Throw ”an empty list ”②Node<T>* temp=front->next;b:while(temp->next)c:cout<<temp->data<<" ";d:temp=temp->next;(4) 获取链表长度函数自然语言描述:a:判断该链表是否为空链表,如果是,输出长度0b:如果不是空链表,新建立一个temp指针,初始化整形数n为0c:将temp指针指向头结点d:判断temp指针指向的结点的next域是否为空,如果不是,n加一,否则return ne: 使temp指针逐个后移,重复d操作,直到temp指针指向的结点的next域为0,返回n伪代码描述a:if ront->next==NULLb:Node<T>* temp=front->next;c:while(temp->next)d:temp=temp->next;(5)析构/删除函数自然语言描述:a:新建立一个指针,指向头结点b:判断要释放的结点是否存在,c:暂时保存要释放的结点d:移动a中建立的指针e:释放要释放的指针伪代码描述a:Node <T> * p=frontb:while(p)c:front=pd:p=p->nexte:delete front(6)按位查找函数自然语言描述:a:初始化工作指针p和计数器j,p指向第一个结点,j=1b:循环以下操作,直到p为空或者j等于1①:p指向下一个结点②:j加1c:若p为空,说明第i个元素不存在,抛出异常d:否则,说明p指向的元素就是所查找的元素,返回元素地址伪代码描述a:Node <T> * p=front->next;j=1;b:while(p&&j!=1)①:p=p->next②:j++c:if(!p) throw ”error”d:return p(7)按位查找函数自然语言描述:a:初始化工作指针p和计数器j,p指向第一个结点,j=1b:循环以下操作,找到这个元素或者p指向最后一个结点①:判断p指向的结点是不是要查找的值,如果是,返回j,否则p指向下一个结点,并且j的值加一c:如果找到最后一个结点还没有找到要查找的元素,返回查找失败信息伪代码描述a:Node <T> * p=front->next;j=1;b:while(p)①: if(p->next==x) return jp=p->nextj++c:return “error”(8)插入函数自然语言描述:a:在堆中建立新结点b:将要插入的结点的数据写入到新结点的数据域c:修改新结点的指针域d:修改前一个指针的指针域,使其指向新插入的结点的位置伪代码描述a:Node <T> * s=new Node <T>;b:s-data=p->datac:s->next=p->nextd:p->next=se:p->data=x(9)删除函数自然语言描述:a:从第一个结点开始,查找要删除的位数i前一个位置i-1的结点b:设q指向第i个元素c:将q元素从链表中删除d:保存q元素的数据e:释放q元素伪代码描述a:q=p->nextb:p->next=q->nextc:x=q->datad:delete q2、代码详细分析(插入):(1)从第一个结点开始,查找节点,使它的数据比x大,设p指向该结点:while (x>p->data) { p=p->next;}(2)新建一个节点s,把p的数据赋给s:s->data=p->data;(3)把s加到p后面:s->next=p->next; p->next=s;(4)p节点的数据用x替换:p->data=x;示意图如图所示xp->datas3、关键算法的时间复杂度:O(1)3.程序运行结果1. 流程图:2、结果截图3.测试结论:可以正确的对链表进行插入,删除,取长度,输出操作。
国家开放大学《数据结构》课程实验报告(实验2——线性表)参考答案
//在链表中删除最高分和最低分结点
for(q=head,p=head->next;p!=NULL;q=p,p=p->next)
{
if(p==pmin) { q->next=p->next; p=q; } //删除最低分结点
};
typedef struct pw PW;
//定义链表结点
struct node
{
PW data;
struct node * next;
};
typedef struct node NODE;
NODE *create(int n); //建立单链表
void input(NODE *s,int i); //输入第i个评委信息
(5)遍历链表,累加求和,计算总分及平均分,并输出相关信息。
完整程序
//实验1.1线性表的链接存储结构
#include
#include
#include
#define PWRS 5 //定义评委人数
//定义评委信息
struct pw
{
char name[8]; //姓名
short age; //年龄
float score; //评分
NODE *create(int n)
{
NODE *head,*p,*q;
inti;
p=(NODE*)malloc(sizeof(NODE));
head=p; q=p; p->next=NULL;
for(i=1; i<=n; i++)
{
p=(NODE*)malloc(sizeof(NODE));
数据结构试题2(含答案)
期末样卷参考答案期末样卷参考答案一.是非题(每题2分共20分)分)1. 1. 线性表的链式存储结构优于顺序存储结构。
线性表的链式存储结构优于顺序存储结构。
线性表的链式存储结构优于顺序存储结构。
F2. 2. 栈和队列也是线性表。
如果需要,可对它们中的任一元素进行操作。
栈和队列也是线性表。
如果需要,可对它们中的任一元素进行操作。
F3. 字符串是数据对象特定的线性表。
T4. 在单链表P 指针所指结点之后插入S 结点的操作是:P->next= S ; S-> next = P->next; F 5. 一个无向图的连通分量是其极大的连通子图。
T6. 邻接表可以表示有向图,也可以表示无向图。
T7. 假设B 是一棵树,B ′是对应的二叉树。
则B 的后根遍历相当于B ′的中序遍历。
T 8. 通常,二叉树的第i 层上有2i-1个结点。
F9. 对于一棵m 阶的B -树,树中每个结点至多有m 个关键字。
除根之外的所有非终端结点至少有┌m/2┐个关键字。
F10.对于任何待排序序列来说,快速排序均快于起泡排序。
F 二.选择题(每题2分共28分) 1. 在下列排序方法中,在下列排序方法中,( c )方法平均时间复杂度为0(nlogn)0(nlogn),最坏情况下时间复,最坏情况下时间复杂度为0(n 2);( d )方法所有情况下时间复杂度均为0(nlogn)0(nlogn)。
a. a. 插入排序插入排序插入排序b. b. b. 希尔排序希尔排序希尔排序c. c. c. 快速排序快速排序快速排序d. d. d. 堆排序堆排序堆排序2. 2. 在有在有n 个结点的二叉树的二叉链表表示中,空指针数为(个结点的二叉树的二叉链表表示中,空指针数为( b )。
a. a.不定不定不定 b.n+1 c.n d.n-1 b.n+1 c.n d.n-13. 3. 下列二叉树中,下列二叉树中,( a )可用于实现符号不等长高效编码。
数据结构(第二章 线性表)
2.2 线性表的顺序存储和实现
顺序表-顺序表定义
由上可知,数据的存储逻辑位置由数组的下标决定。 所以相邻的元素之间地址的计算公式为(假设每个数 据元素占有d个存储单元): LOC(ai)=LOC(ai-1)+d 对线性表的所有数据元素,假设已知第一个数据元 素a0的地址为LOC(a0) ,每个结点占有d个存储 单元, 则第i个数据元素ai的地址为: LOC(ai)=LOC(a0)+i*d 线性表的第一个数据元素的位置通常称做起始位置 或基地址。 在使用一维数组时,数组的下标起始位置根据给定 的问题确定,或者根据实际的高级语言的规定确定。
2.1 线性表抽象数据类型
线性表的分类
顺序存储结构 (元素连续存储、 随机存取结构) 线性表 ADT 链式存储结构 (元素分散存储) 继承 顺序表类 排序顺序表类 继承 单链表类 循环单链表 双链表 继承 排序循环双链表类 排序单链表类
单链表
双链表
循环双链表类
线性表的存储结构
2.2 线性表的顺序存储和实现
线性表的基本操作 求长度:求线性表的数据元素个数。 访问:对线性表中指定位置的数据元素进行存取、替 换等操作。 插入:在线性表指定位置上,插入一个新的数据元素, 插入后仍为一个线性表。 删除:删除线性表指定位置的数据元素,同时保证更 改后的线性表仍然具有线性表的连续性。 复制:重新复制一个线性表。 合并:将两个或两个以上的线性表合并起来,形成一 个新的线性表。 查找:在线性表中查找满足某种条件的数据元素。 排序:对线性表中的数据元素按关键字值,以递增或 递减的次序进行排列。 遍历:按次序访问线性表中的所有数据元素,并且每 个数据元素恰好访问一次。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(1)Leabharlann p = p->next; j++;
}
if(j != i - 1){
printf("插入位置参数错!"); return 0; }
(2) if((q = (SLNode *)malloc(sizeof(SLNode))) == NULL)
exit(1);
q->data = x;
(3) q->next = p->next;
p->next=q->next; //将a、c两结点相连,淘汰b结点;
1、初始化 void ListInitiate(SLNode **head) /*初始化*/ { /*如果有内存空间,申请头结点空间并使头指针head指向头
结点*/ if((*head = (SLNode *)malloc(sizeof(SLNode))) == NULL) exit(1); (*head)->next = NULL; /*置链尾标记NULL */ }
}student,*pointer;
注意:student和student同名但不同意。同名是为了表述起 来方便。 例如,若结构名为student,其新定义名缩写也最好写成 student,因为描述的对象相同,方便阅读和理解。
问2:结构体中间的那个struct Node是何意? 答2:在“缩写” SLNode还没出现之前,只能用原始的 struct Node来进行变量说明。此处说明了指针分量的数 据类型是struct Node。
//最后一个元素要单独处理
p->next=NULL ;} //单链表尾结点的指针域要置空!
新手特别容易忘记!!
5
void display() /*字母链表的输出*/
{p=head;
sum=0;
while (p) //当指针不空时循环(仅限于无头结点的情况)
{printf("%c",p->data);
2
例: 单链表的建立和输出 例:用单链表结构来存放26个英文字母组成的线
性表(a,b,c,…,z),请写出C语言程序。
实现思路:先开辟头指针,然后陆续为每个结点开辟存储 空间并及时赋值,后继结点的地址要提前送给前面的指针。
先挖“坑”,后种“萝 卜”!
3
将全局变量及函数提前说明:
#include<stdio.h> #include<stdlib.h> typedef struct node{ char data; struct node *next; }node;
9
3、向单链表中插入一个元素
在链表中插入一个元素X 的示意图如下:
p
a
b
p
a
b
p->next
插入X
qX
s->next
链表插入的核心语句:
Step 1:q->next=p->next; Step 2:p->next=q ;
X 结点的生成方式:
m=sizeof(SLNode);
q=(SLNode *)malloc(m); q->data=X ;
讨论:
对于线性表的单链表存储结 构描述:
typedef struct Node { DataType data; struct Node *next;
}SLNode, *LinkList;
请注意:typedef不可能创造 任何新的数据类型,而仅仅是 在原有的数据类型中命名一个 新名字,其目的是使你的程序 更易阅读和移植。
p->next = q; (4)
return 1; } 注:此单链表是带头结点的
11
4、从 单链表中删除一个元素
在链表中删除某元素b的示意图如下: p
a ×b × c
p->next
q
(p->next) -> next
删除动作的核心语句(要借助辅助指针变量q):
q = p->next;
//首先保存b的指针,靠它才能找到c;
问1:第一行的Node 与最后一行的SLNode是不是一回事?
答1:不是。前者Node是结构名,后者SLNode是对整个 struct类型的一种“缩写”,是一种“新定义名”,它只 是对现有类型名的补充,而不是取代。
1
typedef struct student { char name; int age;
p=head;
for( i=1; i<26; i++) //因尾结点要特殊处理,故i≠26
{ p->data=i+‘a’-1; // 第一个结点值为字符a
p->next=(node*)malloc(m); //为后继结点“挖坑”!
p=p->next;}
//让指针变量P指向后一个结点
p->data=i+‘a’-1;
思考:Step1和2能互换么? q->next= ?
10
int ListInsert(SLNode *head, int i, DataType x)
{ SLNode *p, *q; int j;
p = head; j = -1;
while(p->next != NULL && j < i - 1) {
node *p,*q,*head; //一般需要3个指针变量
int n ;
// 数据元素的个数
int m=sizeof(node); /*结构类型定义好之后,每个node类型的 长度就固定了,m求一次即可*/
4
void build( ) //字母链表的生成。要一个个慢慢链入
{ int i;
head=(node*)malloc(m); //m=sizeof(node) 前面已求出
8
2、求单链表中数据元素的个数
int ListLength(SLNode *head) {
SLNode *p = head; /*p指向头结点*/ int size = 0; /*size初始为0*/ while(p->next != NULL) /*循环计数*/ {
p = p->next; size ++; } return size; }
p=p->next;
//让指针不断“顺藤摸瓜”
}
sum++;
}
讨论:要统计链表中数据元素的个数,该如何改写?
6
void main( ) {
build( ); display( ); } 问:上述建立的单链表带头结点吗?
7
二、单链表的操作实现
定义单链表结点的结构体如下: typedef struct Node { DataType data; struct Node *next; }SLNode;