前言
这是我听老师讲课做的笔记,考试要看的。
作者:RodmaChen
关注我的csdn博客,更多数据结构与算法知识还在更新
这是我做的数据结构的笔记大家可一去看看
1、 三个基本概念
数据项 是最小的不可分隔的数据单位
数据元素 是最基本处理单位
数据对象 是同种类型数据元素的集合
2、 数据结构包括:逻辑结构、存储结构、运算(操作)三方面内容
逻辑结构(集合、线性、树、图)
线性结构特点是一对一。
树特点是一对多
图特点是多对多
存储结构(顺序、链式、索引、散列)
操作(定义在逻辑结构、实现在存储结构)
3、 算法的概念
4、 五大特点
有穷性、确定性、可行性、输入、输出
5、 算法的度量
时间复杂度(f(n) n代表问题的规模,o(f(n))
空间复杂度
6、 语句的频度
① A.操作对象 B.计算方法 C.逻辑存储 D.数据映像
② A.结构 B.关系 C.运算 D.算法
【分析】数据结构是一门研究非数值计算程序设计中计算机的操作对象以及它们之间关系和运算等的学科。
【答案】① A ② B
A.动态结构和静态结构 B.紧凑结构和非紧凑结构
C.线性结构和非线性结构 D.内部结构和外部结构
【分析】数据的逻辑结构有两类,分别是线性结构和非线性结构。
【答案】C
A.随机存取 B.顺序存取 C.索引存取 D.散列存取
【分析】顺序存储结构是一种随机存取结构,链式存储结构是一种顺序(一个个结点的查找)存取结构。
【答案】① A ② B
for (i=0;i
A.O(m2) B.O(n2) C.O(m×n) D.O(m+n)
【分析】第一个for循环执行m次,第二个for循环执行n次,两个for循环嵌套起来共执行m×n次。
【答案】C
【答案】①一对一;② 一对多;③多对多
【答案】有穷性;确定性;可行性;输入;输出
1、 逻辑结构为线性表(1:1、同一线性表中的数据元素必须同种类型、n代表线性表的表长)
2、 两种存储-顺序表(随机存取、物理相邻体现逻辑相邻)
语言描述、操作(查找、插入、删除、逆序、两表合并)
Typedef struct
{datatype data[MAXSIZE];
Int length;}SqList;
SqList l ; l.data[2]
3、 两种存储-链表(顺序存取,单向链表、单循环链表、双链表、双循环链表)
语言描述、操作(查找、插入、删除、逆序、两表合并,单链表倒数)
Typedef struct node
{datatype data;
Struct node *next;}*LinkList ,ListNode;
两种存储结构的运算:
(1) 顺序表的查找、单链表的查找
(2) 顺序表的插入和删除、单链表的插入和删除
(3) 链表的合并(递增的两个链表合并为递增或递减的单链表,将一个链表头链到另一个链表尾)
(4) 顺序表和单链表就地逆序
A.head== NULL B.head->next== NULL
C.head->next==head D.head!=NULL
【分析】链表为空时,头结点的指针域为空。
【答案】B
A.单链表 B.仅有头指针的单循环链表
C.双链表 D.仅有尾指针的单循环链表
【分析】根据题意要求,该线性表的存储应能够很方便地找到线性表的第一个元素和最后一个元素,A和B都能很方便地通过头指针找到线性表的第一个元素,却要经过所有元素才能找到最后一个元素;选项C双链表若存为双向循环链表,则能很方便地找到线性表的第一个元素和最后一个元素,但存储效率要低些,插入和删除操作也略微复杂;选项D可通过尾指针直接找到线性表的最后一个元素,通过线性表的最后一个元素的循环指针就能很方便地找到第一个元素。
【答案】D
A.O(log2n) B.O(1)
C.O(n) D.O(n2)
【分析】在第i个位置上插入新元素需要从最后一个元素开始后移直到第i个元素后移为止,后移元素的次数为n-i+1,即时间复杂度为O(n)。
【答案】C
A.p->next=s; s->prior=p; p->next->prior=s; s->prior=p->next;
B.p->next=s; p->next->prior=s; s->prior=p; s->next=p->next;
C.s->prior=p; s->next=p->next; p->next=s; p->next->prior=s;
D.s->prior=p; s->next=p->next; p->next->prior=s; p->next=s;
【分析】由于要将s所指结点插入到p所指结点之后,p结点为s结点的前驱,s结点为p结点的新后继,而结点p的原后继结点为结点s的后继结点,结点s为结点p的原后继结点的前驱结点。在选项A、B和C中均是先执行操作p->next=s,就是修改了结点p的后继结点为s结点,然后再执行操作p->next->prior=s,因此,无法使得结点s为结点p的原后继结点的前驱结点,这样的赋值会使s结点为其自身的前驱。应先执行操作p->next->prior=s,再执行操作p->next=s。
【答案】D
A.s->next=p->next;p->next=s;
B.p->next=s->next;s->next=p;
C.q->next=s; s->next=p;
D.p->next=s; s->next=q;
【分析】由于是将s所指结点插入到q和p所指结点之间,即使其为q所指结点的后继结点,为p所指结点的前驱结点,因此s->next的取值应为p,p->next的取值无需改动,q->next的取值应改为s,故A、B和D均是错误的。【答案】C
【分析】因为顺序表在内存是用地址连续的空间存储的,设 a1的存储地址为Loc(a1),每个数据元素占d个存储地址,则第i个数据元素的地址为:
Loc(ai)=Loc(a1)+(i-1) *d 1<=i<=n
这就是说只要知道顺序表首地址和每个数据元素所占地址单元的个数就可求出第i个数据元素的地址来,这也是顺序表具有按数据元素的序号随机存取的特点。
【答案】正确
s->prior = p->prior;
p->prior=s;
s->next=p;
【解答】
只能是:s->prior->next=s; 而不能为:
p->prior->next=s;
【解答】
头指针是一个指针变量,里面存放的是链表中首结点的地址,并以此来标识一个链表。如链表H,链表L等,表示链表中第一个结点的地址存放在H、L中。
头结点是附加在第一个元素结点之前的一个结点,头指针指向头结点。当该链表表示一个非空的线性表时,头结点的指针域指向第一个元素结点,为空表时,该指针域为空。
开始结点指第一个元素结点。
头指针的作用是用来惟一标识一个单链表。
头结点的作用有两个:一是使得对空表和非空表的处理得以统一。二是使得在链表的第一个位置上的操作和在其他位置上的操作一致,无需特殊处理。
【提示】先在单链表中顺序比较,找到插入位置,再生成结点,插入。
typedef struct node{
int data;
struct node *next;
}Lnode,*Linklist;
Linklist insert(Linklist L,int x){
//将值为x 的结点插入到有序的单链表L中
Lnode *p,*s;
p=L;
while (p->next && x>p->next->data)
p=p->next; //找插入位置
s=new Lnode;
s->data=x; //申请、填装结点
s->next=p->next;
p->next=s; //插入到链表中去
return L;
}
1、栈的特点是什么?栈和线性表的区别是什么?
答:只允许在线性表的同一端进行插入和删除的线性表。做插入和删除那一端叫做栈顶,不能做插入和删除的那一端叫做栈底。
线性表则是只要是合法的位置都可以做插入和删除。
2、先进后出(FILO, First In Last Out)或后进先出(LIFO)
3、如果入栈的顺序为ABC,则出栈的顺序可以为ABC,CBA,BAC,BCA等。
4、顺序栈:顺序存储结构的栈称为顺序栈。
链栈: 链式存储结构栈称为链栈。
5、顺序栈的语言描述(静态)
#define StackSize 100
typedef char DataType;
typedef struct
{ DataType data[StackSize];
int top;
}SeqStack;
SqStack sq;
6、动态语言描述(教材):
typedef struct
{ selemtype *base;
selemtype *top;
int stacksize;
}SqStack;
SqStack sq;
sq.base=(selemtype *)malloc(Maxsize*sizeof(selemtype));
sq.top=sq.base;
7、静态和动态下的栈空、入栈、出栈、读栈顶元素、栈满的操作
8、顺序栈静态运算的实现
9、顺序栈动态运算的实现
一、队列的特点?队列和栈的区别?线性表的特点?
答:队列指的是一端做插入(队尾),另一端做删除(队头)。
二、如果入队顺序为ABC,则出队顺序只能是ABC
如果入栈为ABC,则出栈顺序可以有ABC,BAC,CBA,ACB等。
三、队列可以采取顺序存储(顺序队)和链式存储(链队)
四、顺序队的静态实现
1.结构体语言描述
typedef struct queue
define MAXSIZE 1024 /*队列的最大容量*/
typedef struct
{datatype data[MAXSIZE]; /*队员的存储空间*/
int rear,front; /*队头队尾指针*/
}SeQueue;
定义一个指向队的指针变量:
SeQueue *sq;
2.静态实现的基本操作
假溢出现象,提出了循环队列。
3.什么是循环队列?
循环队列中rear和front操作要会。
4.循环队列的语言描述,这个实际上和前面的顺序队的语言描述一样
语言描述:
typedef struct
{ datatype data[m] ;
int front ; int rear ;
int count ; //统计队列中元素点数
} cirqueue ;
cirqueue *q
5.循环队列的基本操作
五、循环队列的动态语言描述以及基本操作
七、链队
指的是在单链表的首结点上做删除,在尾结点上做插入。
八、理解顺序表、顺序栈、顺序队的区别?
理解链表、链栈、链队的区别?
顺序表:可以在任意合法的位置上做插入和删除。
顺序栈:只可以在顺序表的同一端上做插入和删除。
顺序队:在顺序表的一端做插入,另一端做删除。
链表:可以在任意合法的位置上做插入和删除。
链栈:只可以在链表的首结点位置做插入和删除。
链队:在链表的首结点位置做删除,尾结点后做插入。
A.2 B.3 C.5 D.6
【分析】s1、s2进栈后,此时栈中有2个元素,接着s2出栈,栈中尚有1个元素s1;s3、s4 进栈后,此时栈中有3个元素,接着s4、s3出栈,栈中尚有1个元素s1;s5、s6 进栈后,此时栈中有3个元素,接着s6、s5出栈,栈中尚有1个元素s1;s1出栈后,此时栈为空栈。由此可知,栈的容量至少应该是3。
【答案】B
A.a3 a1 a4 a2 B.a3 a2 a4 a1 C.a3 a4 a2 a1 D.a4 a3 a2 a1
【分析】由于a1、 a2 、a3 已进栈,此时,栈顶元素为a3,不管a4何时进栈,出栈后,a1、a2 、a3的相对位置一定是不变的,这就是a3一定在前,a2一定居中,a1一定在后。比较上述4个答案,只有A中的a1出现在 a2 的前面,这显然是错误的。
【答案】A
A.top->next=s; B.s->next=top->next; top->next=s;
C.s->next=top; top=s; D.s->next=top; top=top->next;
【分析】本操作是在链栈上的进栈操作。操作顺序应该是先插入结点,再改变栈顶指针。
【答案】C
A.x=top->data; top=top->next; B.top=top->next; x=top->data;
C.x=top; top=top->next; D.x=top->data;
【分析】本操作是在链栈上进行出栈操作,操作顺序应该是先保存被删除结点的值,然后再改变栈顶指针的值。
【答案】A
A.通常不会出现栈满的情况 B.通常不会出现栈空的情况
C.插入操作更加方便 D.删除操作更加方便
【分析】不管是链栈还是顺序栈,其插入、删除操作都是在栈顶进行的,都比较方便,所以不可能选C,D。对链栈来说,当栈中没有元素而又要执行出栈操作时,就会出现栈空现象,故B也是不正确的。只要内存足够大,链栈上就不会出现栈满现象。而对顺序栈来讲,由于其大小是事先确定好的,因此可能会出现栈满现象。
【答案】A
A.sq.front=(sq.front+1)%m B.sq.front=(sq.front+1)%(m+1)
C.sq.rear=(sq.rear+1)%m D.sq.rear=(sq.rear+1)%(m+1)
【分析】首先,执行的入队操作是在队尾进行的,故A,B肯定是不对的。其次,由于存放sq的数组为A[m],数组元素为A[0]~a[m-1],共有m个单元,%运算中的模应为m。
【答案】C
A.f->next=c; f=s; B.r->next=s; r=s;
C.s->next=r; r=s; D.s->next=f;f=s;
【分析】插入操作总是在队尾进行,而且应该先插入结点,再改变队尾指针的值。
【答案】B
【分析】由于只能在栈顶处执行插入、删除操作,使得数据元素的进栈顺序恰好与出栈顺序相反,所以栈的逻辑特点是先进后出(或后进先出)。而对于队列来说,插入、删除操作必须在队列的两端进行,数元素的进队顺序是一致的,所以队列的逻辑特点是先进先出(或后进后出)。两者的共同特点是所有操作只能在端点处进行。
【答案】先进后出(或后进先出);先进先出(或后进后出);端点;栈是在同一端插入和删除,队列是在一端插入而在另一端删除。
一、数组不能做插入和删除,只能做取值和赋值操作。
二、数组只能采取顺序存储(行优先和列优先)
三、数组行优先计算公式(下标从0和1开始)
数组列优先计算公式(下标从0和1开始)
四、为什么要对特殊矩阵进行压缩存储?
答:主要为了节省存储空间。
五、对称矩阵和三角矩阵各长什么样?
六、F[k],对称矩阵的压缩存储所需存储空间至少n(n+1)/2。存储计算公式。
三角矩阵的压缩存储所需存储空间至少n(n+1)/2+1。
七、对称矩阵的压缩存储可以存其下三角上的元素或其上三角上的元素。了解公式
八、三角矩阵的压缩存储可以存其下三角上的元素或其上三角上的元素。但是必须多一个单元存常数C. 了解公式
九、稀疏矩阵长什么样?
十、稀疏矩阵存储方法有两种:三元组表和十字链表
十一、了解广义表,了解广义表取表头和表尾操作。
【分析】
按行优先方式存储时,M[7][5]的前面已经存放了75(7×10+5=75)个元素,它们共占用了75×3=225个字节,所以M[7][5]的起始地址为EA+225。
按列优先方式存储时,M[7][5]的前面已经存放了47(5×8+7=47)个元素,它们共占用了47×3=141个字节,所以M[8][5]的起始地址为EA+141。
【答案】EA+225;EA+141
【解答】
因为4×5×6=120,所以二维数组A5×6共占120个字节;
LOC(a45)=1000+120-4=1116;
按行优先时LOC(a25)=1000+4×(2×6+5)=1068;
按列优先时LOC(a25)=1000+4×(5×5+2)=1108。
1、树的相关定义
树分为有序树和无序树
树高 度
2、二叉树的性质和存储
第 i层最多 2 i − 1 2^{i-1} 2i−1 前k层至多 2 k − 1 2^k-1 2k−1 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1 n 0 = 2 n 3 + n 2 + 1 n_0=2n_3+n_2+1 n0=2n3+n2+1
顺序存储(完全二叉树)
链式二叉
3、二叉树的遍历
前序、中序、后序
给出一棵二叉树,写出先中后序列
给先+中 后+中 写出另一种序列
递归写算法
3、线索化二叉树
4、树和森林与二叉树的转换
5、赫夫曼树
6、递归在树的求解问题中的应用
A.二叉树中任何一个结点的度都为2
B.二叉树的度为2
C.一棵二叉树的度可小于2
D.任何一棵二叉树中至少有一个结点的度为2
【分析】二叉树是树形结构的一种,但不是二度树,也不是二度树的特例,比如二叉树包括空树,也包括只有一个根结点的情况,也包括只有度为0和度为1结点的情况。
【答案】C
【分析】因为这样才能保证其带权路径长度最短。
【答案】正确
【分析】对于非完全二叉树进行顺序存储时需按照完全二叉树顺序存储的顺序将空结点也存入。
【答案】错误
【分析】当二叉树只有一个结点时,三种遍历序列均相同。
【答案】正确
【分析】深度为k的完全二叉树最少结点时是前k-1层为满二叉树,第k层只有一个结点,故有2k-1 个结点;深度为k的完全二叉树最多结点时是k层的满二叉树。
【答案】2k-1;2k-1
【解答】
(1)知道二叉树的前序序列和中序序列能惟一确定一棵二叉树,(1)对应的二叉树如图(1)所示。
(2)知道二叉树的中序序列和后序序列能惟一确定一棵二叉树,(2)对应的二叉树如图(2)所示。
(3)知道二叉树的前序序列和后序序列不能惟一确定一棵二叉树,如图(3)所示的两棵二叉树的前序和后序序列是相同的。
根据前序、中序和后序的遍历特点,如果知道一棵树的前序序列,则第一个结点就是根结点,后序序列的最后一个结点是根结点,但都没有办法确定左右子树,而对于中序来说,当知道了根结点之后,恰好能分离出左右子树来,因此在二叉树中的结点值均不相同的情况下,则由二叉树的前序序列和中序序列,或由其后序序列和中序序列均能惟一地确定一棵二叉树,而由前序序列和后序序列却不能惟一地确定一棵二叉树。
(1)为这8个字母设计哈夫曼编码。
(2)若用三位二进制数(0~7)对这8个字母进行等长编码,则哈夫曼编码的平均码长是等长编码的百分之几?它使电文总长平均压缩多少?
【解答】
(1)首先构造哈夫曼树:
根据哈夫曼树,各字符的编码如下:
字符 频率 编码
a 0.07 0000
b 0.19 10
c 0.02 00100
d 0.06 0011
e 0.32 01
f 0.03 00101
g 0.21 11
h 0.10 0001
(2)哈夫曼编码平均码长为:
4×0.07+2×0.19+5×0.02+4×0.06+5×0.03+2×0.21+4×0.1=2.71
因为等长编码的平均码长为3,所以哈夫曼编码是等长编码的2.71/3=0.90,它使电文平均压缩了近10%。
【分析】
空二叉树的深度为0,对非空二叉树,其深度等于根结点的左子树和右子树中深度较大者的子树的深度加1。故根据如下表达式采用后序递归遍历算法实现:
【算法】
int Depth(BiTree T){
int dep1,dep2;
if (T==NULL)
return 0;
else{
dep1=Depth(T->lchild); //求左子树的深度
dep2=Depth(T->rchild); //求右子树的深度
if (dep1>dep2)
return dep1+1;
else
return dep2+1;
}
}
【分析】
依题意,设t 为一棵用二叉链表存储的二叉树,则交换各结点的左右子树的运算基于后序遍历实现:交换左子树上各结点的左右子树;交换右子树上各结点的左右子树;再交换根结点的左右子树。
【算法】
void Exchg(BiTree *t){
BinNode *p;
if (t){
Exchg(&((*t)->lchild));
Exchg(&((*t)->rchild));
P=(*t)->lchild;
(*t)->lchild=(*t)->rchild;
(*t)->rchild=p;
}
}
(1)它的顺序存储结构示意图。
(2)它的二叉链表存储结构示意图。
(3)它的三叉链表存储结构示意图。
二叉树的先序次序访问序列为:GFKDAIEBCHJ。
二叉树的中序访问次序为:DIAEKFCJHBG。
二叉树的后序次序访问序列为:CFEGDBJLKIHA。
二叉树的中序访问次序为:CBEFDGAJIKLH。
二叉树的层次序列为:ABCDEFGHIJ。
二叉树的中序次序为:DBGEHJACIF。
【提示】采用递归算法实现。
int count(BiTree t){
if (t==NULL)
return 0;
else
return count(t->lchild)+count(t->rchild)+1;
}
A.存在这样的二叉树,对其采用任何次序的遍历其结点访问序列均相同。
B.二叉树是树的特殊情形。
C.由树转换成二叉树,其根结点的右子树总是空的。
D.在二叉树只有一棵子树的情况下,也要指出是左子树还是右子树。
【分析】二叉树的特点是仅有一个分支时也有左右之分,而树无此特点,也即二叉树不是树的特殊情形。
【答案】B
【分析】由树转换成二叉树,根结点必有左子树而没有右子树。
【答案】错误
一、基本概念
n(n-1)
和无向完全图n(n-1)/2
(1)写出从顶点v0出发进行深度优先搜索:v0 v1 v2 v3
(2)写出从顶点v0出发进行广度优先搜索vo v1 v3 v2。
四、对下面连通图,请分别用Prim和Kruskal 算法构造其最小生成树。
本人博客:https://blog.csdn.net/weixin_46654114
本人b站求关注:https://space.bilibili.com/391105864
转载说明:跟我说明,务必注明来源,附带本人博客连接。
请给我点个赞鼓励我吧