数据:能输入到计算机中并能被计算机程序识别和处理的符号
数据元素:数据的基本单位,在计算机中通常作为一个整体进行考虑和处理
数据项:构成数据元素的最小单位
数据结构:相互之间存在一定关系的数据元素的集合。分为逻辑结构和存储结构。
逻辑结构:数据元素以及数据元素之间的逻辑关系,在形式上可以定义为一个二元组:(D,R),其中,D是数据元素的有限集合,R是D上的关系集合。
存储结构(物理结构):数据及其逻辑结构在计算机中的表示。存储结构除了存储数据元素之外必须隐式或显式地存储数据元素之间的逻辑关系。通常有两种存储结构:顺序存储结构和链式存储结构
算法:对特定问题求解步骤的一种描述,是指令的有限序列
算法的基本特性:
好算法特性:
算法的描述方法:
常见时间复杂度: 算法运行时间计算: for循环 假设循环体的时间复杂度为O(n)循环次数为m,则这个循环的时间复杂度为O(nm); 嵌套的for循环 由内外各个循环的复杂度为O(a)、O(b)、O©…则这个嵌套循环时间复杂度为O(abc…) 顺序语句 各个语句运行时间求和(或取较大值) if/else语句 总的时间复杂度最大的路径的时间复杂度 :算法在执行过程中需要的辅助空间数量,也就是除算法本身和输入输出数据所占用的空间外,算法临时开辟的存储空间 线性表的特点: 基本思想:用一段地址连续的存储单元依次存储线性表的数据元素 顺序表的优点: 顺序表的缺点: 第i个元素的存储地址: Loc(ai) = Loc(a1) + (i-1)*c 插入 删除 查找 按值查找 按位查找 :用一组任意的存储单元存放线性表的元素,这组存储单元可以连续也可以不连续甚至可以零散分布在内存中的任意位置。 存储特点: 建立 头插法 尾插法 插入 删除 遍历 栈:限定仅在表的一端进行插入和删除操作的线性表 栈顶:允许插入和删除的一端为栈顶 栈底:另一端 特点: 进栈 出栈 队列:只允许在一端进行插入操作,在另有但进行删除操作的线性表 队尾:允许插入的一端 队头:允许删除的一端 特点: 进队 SeqQueue[++rear] = x ; 出队 x = SeqQueue[++front]; 进队 出队 进队 出队 按行优先存储 按列优先存储 对称矩阵压缩 注意!这里的i和j是从1开始的(一开始没看见,算半天不一样…) 三角矩阵压缩 结点:在树中通常讲数据元素称为结点 树:是n(n≥0)个结点的有限集合。 结点的度:某结点所拥有的子树的个数 树的度:树中各结点度的最大值 叶子结点(终端结点):度为0的结点 分支结点(非终端结点):度不为0的结点 结点的层数:根结点的层数为 1;对其余结点,若某结点在第 k 层,则其孩子结点在第 k+1 层 树的深度(高度):树中所有结点的最大层数 树的宽度:树中每一层结点个数的最大值 有序树、无序树:如果一棵树中结点的各子树从左到右是有次序的,称这棵树为有序树;反之,称为无序树。 求度为k的结点个数 遍历每一个结点,如果该结点具有k个孩子,则cnt++ 求叶子结点个数 如果一个结点的左右都儿子为空,则为叶子结点,cnt++ 二叉树: n(n≥0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成 二叉树的特点: 特殊的二叉树: 斜树 左斜树:所有结点都只有左子树的二叉树 右斜树:所有结点都只有右子树的二叉树 特点: 满二叉树 :所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上的二叉树 完全二叉树 :在满二叉树中,从最后一个结点开始,连续去掉任意个结点得到的二叉树 【答案】B 【解析】当深度为1时 ⭐对于一颗具有n个结点的树,其所有结点的度之和为n-1 求叶子,二叉树的高度,左右子树的交换,求结点的双亲,结点个数 森林:m(m≥0)棵互不相交的树的集合。 森林的遍历: 树的前序遍历序列等于对应二叉树的前序遍历序列 树的后序遍历序列等于对应二叉树的中序遍历序列 相关概念: 图:由顶点的有穷非空集合和顶点之间边的集合组成 无向图:图中任意两个顶点之间的边都是无向边 有向图:图中任意两个顶点之间的边都是有向边 带权图(网图):边上带权的图 稠密图:边数很多的图 稀疏图:边数很少的图 路径、路径长度、回路 路径长度: 非带权图——路径上边的个数 带权图——路径上边的权值之和 回路(环):第一个顶点和最后一个顶点相同的路径 简单路径、简单回路 简单路径:序列中顶点不重复出现的路径 简单回路(简单环):除了第一个顶点和最后一个顶点外,其余顶点不重复出现的回路 子图 连通图、连通分量 强连通图、强连通分量 求顶点数、边数 求有向图的入度和出度 根据存储结构 空间复杂度:O(n^2) 特点: 求顶点v的度: 求顶点i的邻接点: 求顶点v的入度: 求顶点v的出度: 1.图的邻接矩阵采用数组方式进行存储,因此属于顺序存储结构。(×) 【解析】图没有顺序存储结构 2.无向图的邻接矩阵一定是对称的,有向图的邻接矩阵一定是不对称的。(×) 【解析】当顶点间存在方向相反的弧 空间复杂度:O(n+e) 求顶点v的度 顶点v边表中的结点个数 求顶点v的所有邻接顶点 遍历顶点v边表中的所有结点 求顶点v的出度 求顶点v的入度 存储结构定义: 空间性能比较 时间性能比较 查找某顶点的所有邻接点 邻接矩阵:O(n) 邻接表:O(e/n) 唯一性比较 对应关系 基本思想: 时间复杂度:O(n^2) 时间复杂度: 基本思想: 时间复杂度:O(n^2) 生成树:连通图的生成树是包含全部顶点的一个极小连通子图 生成树的代价:在无向连通网中,生成树上各边的权值之和 最小生成树:在无向连通网中,代价最小的生成树 时间复杂度:O(n^2) 时间复杂度:O(elog2e)+O(elog2n) = O(elog2e) O(elog2e)用于对边集数组进行排序 基本思想 1.在一个有向图的拓扑序列中,若顶点a在顶点b之前,则图中必有一条弧(×) 2.若一个有向图的邻接矩阵中对角线以下元素均为零,则该图的拓扑序列必定存在(√) 3.拓扑排序算法可以用栈或者队列保存入度为0的顶点(√) 关键路径:AOE网中从源点到终点的最长路径 关键活动:关键路径上的活动 基本思想 设带权有向图 G=(V,E)含有 n 个顶点 e 条边,设置 4 个一维数组: (2)事件的最迟发生时间 vl[n] (3)活动的最早开始时间 ae[e] (4)活动的最晚开始时间 al[e] 时间复杂度: 二叉排序树(二叉查找树):或者是一棵空的二叉树,或者是具有下列性质的二叉树: 二叉排序树的存储:二叉链表 时间复杂度: 平衡因子:该结点的左子树的深度减去右子树的深度 平衡二叉树:或者是一棵空的二叉排序树,或者是具有下列性质的二叉排序树: 最小不平衡子树:以距离插入结点最近的、且平衡因子的绝对值大于 1 的结点为根的子树 散列表:采用散列技术存储查找集合的连续存储空间 散列函数:将关键码映射为散列表中适当存储位置的函数 散列函数是关键码的线性函数,即: H(key) = a × key + b (a,b为常数) 适用于:事先知道关键码,关键码集合不是很大且连续性较好 对关键码平方后,按散列表大小,取中间的若干位作为散列地址 适用于:事先不知道关键码的分布且关键码的位数不是很大 散列函数:H(key)=key mod p 如何选取合适的 p,才能产生较少的同义词? :小于等于表长(最好接近表长)的最小素数或不包含小于20质因子 适用于:最简单、最常用,不要求事先知道关键码的分布 处理冲突的办法:用拉链法处理冲突得到的散列表 拉链法: 构造 查找 处理冲突的办法:用开放定址法处理冲突得到的散列表 开放定址法: 寻找空的散列地址的方法: 查找算法 排序算法的稳定性:假定在待排序的记录序列中存在多个具有相同关键码的记录,若经过排序,这些记录的相对次序保持不变,则称这种排序算法稳定,否则称为不稳定。 稳定性:稳定 稳定性:稳定 稳定性:不稳定 稳定性:不稳定
O( l o g 2 n {log_2{n}} log2n)
n=1000;
k=0;
for a in range(n):
k+=1
for a in range(n):
for b in range(n):
k+=1
3.2算法的空间复杂度
二、线性表
2.1 线性表
2.2 线性表的顺序存储结构——顺序表
2.2.1 顺序表的特点
2.2.2 元素的存储地址
2.2.3 顺序表的实现
const int MaxSize=100;
template
template
template
template
template
2.3 线性表的链接存储结构
2.3.1 单链表
2.3.2 单链表的实现
template
template
template
template
template
template
void LinkList
2.4 顺序表与链表的比较
2.4.1 存储分配方式
2.4.2 空间性能比较
2.4.3 时间性能比较
2.4.4 结论
三、栈和队列
3.1 栈
3.1.1 定义
3.1.2 顺序栈
3.1.2.1 顺序栈的实现
const int StackSize = 10;
template
template
template
3.2 队列
3.2.1 定义
3.2.2 顺序队列
3.2.3 循环队列
3.2.3.1 循环队列的实现
const int QueueSize = 100;
template
template
template
3.2.4 链队列
template
template
template
四、字符串多维数组
4.1 KMP算法
4.2 二维数组
4.3 压缩存储
五、树和二叉树
5.1 树的定义和基本术语
5.1.1 树的定义
5.1.2 树的基本术语
5.2 树的存储
双亲表示法
孩子表示法
孩子兄弟表示法
5.3 二叉树
5.3.1 二叉树的定义
5.3.2 二叉树的性质
5.3.3 二叉树的遍历
template
template
template
template
5.3.4 树、森林与二叉树的转换
树转换为二叉树
森林转换为二叉树
二叉树转换为树或森林
5.3.5 哈夫曼编码
5.3.5.1 构造哈夫曼树
struct ElemType{
int weight;//权值
int parent,lchild,rchild;
}
HuffmanTree(int w[], int n){
huffTree = new ElemType[2*n-1];
//1.初始化
for(int i=0;i<2*n-1;i++){
huffTree[i].parent = -1;
huffTree[i].lchild = -1;
huffTree[i].rchild = -1;
}
//2.赋权值
for(int i=0;i
5.3.5.2 哈夫曼编码
六、图
6.1 图的定义和基本术语
6.1.1 图的定义
6.1.2 图的基本术语
6.2 图的存储
6.2.1 邻接矩阵
6.2.1.1 无权图的邻接矩阵
6.2.1.2 带权图的邻接矩阵
6.2.1.3 邻接矩阵的建立
const int MaxSize = 10;
template
template
6.2.2 邻接表
p = adjlist[v].firstEdge; count = 0;
while (p != nullptr)
count++; p = p->next;
p = adjlist[v].firstEdge;
while (p != nullptr)
{
j = p->adjvex; //j是v的邻接点
p = p->next;
}
struct EdgeNode
{
int adjvex;
EdgeNode *next;
};
template
6.2.2.1 邻接表的建立
const int MaxSize = 10;
template
tempalte
6.2.3 邻接矩阵与邻接表的比较
6.3 图的遍历
6.3.1 图的深度优先遍历
邻接矩阵中
visited[MaxSize];
template
邻接表中
int visited[MaxSize];
template
6.3.2 图的广度优先遍历
邻接矩阵中
visited[MaxSize];
template
邻接表中
visited[MaxSize];
template
6.4 最小生成树
6.4.1 Prim算法(加点法)
void Prim(int v){
int lowcost[MaxSize],adjvex[MaxSize];
int k;
for(int i=0;i
6.4.2 Kruskal算法(加边法)
struct EdgeType{
int from, to, weight;
}
const int MaxVertex = 10;
const int MaxEdge = 100;
template
int FindRoot(int parent[], int v){
int t = v;
while(parent[t]>-1)
t = parent[t];
return t;
}
void EdgeGraph
6.5 AOV网与拓扑排序
算法:拓扑排序TopSort
输入:AOV网 G=(V,E)
输出:拓扑序列
1. 重复下述操作,直到输出全部顶点,或AOV网中不存在没有前驱的顶点
1.1 从AOV网中选择一个没有前驱的顶点并且输出;
1.2 从AOV网中删去该顶点,并且删去所有以该顶点为尾的弧;
6.6 AOE网与关键路径
(1)事件的最早发生时间 ve[n]算法:关键路径算法
输入:带权有向图 G=(V,E)
输出:关键活动
1. 计算各个事件的最早发生时间和最晚发生时间ve[n]和vl[n];
2. 计算各个活动的最早开始时间和最晚开始时间ae[e]和al[e];
3. 计算各个活动的时间余量,时间余量为 0 即为关键活动 ;
七、查找技术
7.1 线性表的查找技术
const int MaxSize = 100;
class LineSearch{
public:
LineSearch(int a[], int n);
~LineSearch();
int SeqSearch(int k);
int BinSearch1(int k);
int BinSearch2(int low, int high, int k);
private:
int data[MaxSize];
int length;
}
7.1.1 顺序查找
int SeqSearch(int k){
int i = length;
data[0] = k;
while(data[i]!=k)
i--;
return i;
}
7.1.2 折半查找
递归算法
int BinSearch2(int low, int high, int k){
if(high
非递归算法
int BinSearch1(int k){
int low = 1, high = length,mid;
while(low<=high){
mid=(low+high)>>1;
if(kdata[mid]){
low = mid+1;
}else{
return mid;
}
}
//别漏了当找不到要查询的值的情况!!
return 0;
}
7.2 树表的查找技术
7.2.1 二叉排序树
7.2.1.1 什么是二叉排序树
(1)若它的左子树不空,则左子树上所有结点的值均小于根结点的值
(2)若它的右子树不空,则右子树上所有结点的值均大于根结点的值
(3)它的左右子树也都是二叉排序树7.2.1.2 二叉排序树的类定义
class BiSortTree
{
public:
BiSortTree(int a[ ], int n);
~ BiSortTree( ) {Release(root);}
BiNode
7.2.1.3 二叉排序树的查找
BiNode
7.2.1.4 二叉排序树的插入
BiNode
7.2.1.5 二叉排序树的构造
BiSortTree(int a[ ], int n){
root = nullptr;
for(int i=0 ;i
7.2.1.6 二叉排序树的删除
void DeleteBST(BiNode
7.2.2 平衡二叉树
(1)根结点的左子树和右子树的深度最多相差 1;
(2)根结点的左子树和右子树也都是平衡二叉树;7.2.2.1 平衡二叉树的构造方法
7.2.2.2 平衡二叉树的平衡调整
7.3 散列表的查找技术
7.3.1 散列表
7.3.2 散列函数的设计
7.3.2.1 直接定址法
7.3.2.2 平方取中法
7.3.2.3 除留余数法
7.3.3 开散列表
对于给定的关键码key执行下述操作:
(1)计算散列地址:j = H(key)
(2)将key对应的记录插入到同义词子表 j 中;
const int MaxSize = 100;
class HashTable2
{
public:
HashTable2( );
~HashTable2( );
int Insert(int k);
int Delete(int k);
Node
j = H(k);
Node
Node
7.3.4 闭散列表
对于给定的关键码key执行下述操作:
(1)计算散列地址:j = H(key)
(2)如果地址 j 的存储单元没有存储记录,则存储key对应的记录;
(3)如果在地址 j 发生冲突,则寻找一个空的散列地址,存储key对应的记录;
const int MaxSize = 100;
class HashTable1
{
public:
HashTable1( );
~HashTable1( );
int Insert(int k);
int Delete(int k);
int Search(int k);
private:
int H( );
int ht[MaxSize];
};
HashTable1 :: HashTable1( )
{
for (int i = 0; i < MaxSize; i++)
ht[i] = 0;
}
HashTable1 :: ~HashTable1( )
{
}
int Search(int k){
int i, j=H(k);
i=j;
while(ht[i]!=0){
if(ht[i]==k)
return i;
else
i=(i+1)%MaxSize;
}
return -1;
}
7.3.5 开散列表与闭散列表的比较
八、排序技术
8.1 排序的基本概念
8.2 插入排序
8.2.1 直接插入排序
void InsertSort(){
int i,j,temp;
//排序进行n-1趟
for(i=1;i
8.2.2 希尔排序
void ShellSort(){
int i,j,d, temp;
for(d=length/2;d>=1;d/=2){
for(i=d;i
8.3 交换排序
8.3.1 起泡排序
void BubbleSort(){
int j, exchange, bound, temp;
//用exchange记录最后一次交换的位置
//减少重复的比较
exchange = length-1;
while(exchange!=0){
bound = exchange;
exchange = 0;
for(j=0;j
8.3.2 快速排序
int Partition(int first, int last){
int i=first,j=last;
int temp;
while(i
void QuickSort(int first, int last){
if(first>=last)
return;
else{
int pivot = Partition(first, last);
QuickSort(first,pivot-1);
QuickSort(pivot+1,last);
}
}
8.4 选择排序
8.4.1 简单选择排序
void SelectSort(){
int k;
for(int i=0;i
8.4.2 堆排序
void Sift(int k, int last){
int i=k,j = 2*k+1;
while(j<=last){
if(j
void HeapSort(){
for(int i=ceil(length/2)-1;i>=0;i--){
Sift(i,length-1);
}
for(int i=1;i