HHU 《算法与数据结构》复习指南

复杂度的计算

算法的时间复杂度和空间复杂度计算

抽象数据类型: 描述数据类型的方法不依赖具体方法实现。只描述数据对象集和相关操作集“是什么”,不涉及“如何做到”。

数据结构:数据对象在计算机中的组织方式

注意这部分(指第一个老师的部分)作业答案全是用的老师给的,但是有些代码很离谱,斟酌阅读。。没给答案我就没放,此部分知识点也是随便整理的,请自行复习。。

线性表

线性表(简称为表):是零个或多个元素的有穷序列。

1、顺序表示

顺序表示的线性表也称顺序表

struct SeqList {
	int MAXNUM; /*顺序表中可以存放元素的个数*/
	int n;   /* 实际存放线性表中元素的个数,n≤MAXNUM  */ 
	DataType *element; /*element[0], element[1],…,element[n-1]存放线性表中的元素*/
};
typedef  struct SeqList *PSeqList; //创建一个 SeqList数组,即 PSeqList[] 
2、链接表示
struct Node {/*单链表结点结构*/
	DataType info;
	Node link; //老师写的pnode link , 离谱+1
};
typedef struct Node * LinkList ;    /*单链表类型*/
LinkList  llist; /*llist是一个链表的头指针*/

作业:
在这里插入图片描述

//在palist所指的顺序表中下标为 p的元素之后插入一个值为 x的元素,并返回插入成功与否标志。
int insertAfter_seq(PSeqList palist, int p,  DataType x) {
	int q;
	if (palist->n = = palist-> MAXNUM) {
		prinft("Overflow!\n");
		return 0;
	}
	if (p < -1 ||  p> = palist ->n ) {
		printf("Not exist! \n");
		return 0;
	}

	for (q=palist->n-1; q > p; q--)
		palist -> element[q+1] = palist -> element[q] ;

	palist->element[p+1] = x ;
	palist->n  = palist->n + 1;
	return 1;
}

在这里插入图片描述
物理位置相邻、指针域
在这里插入图片描述

//顺序表
void reverse(PSeqlist palist) { //答案函数是 int reverse 离谱+1
	int p;
	DataType temp;
	if  ((palist ==NULL) && (palist->n==0)) return 0;
	for (p=0; q < palist->n/2; p++) {
		temp = palist -> element[p];
		palist -> element[p] = palist -> element[palist->n-1-p];
		palist -> element[palist->n-1-p]=x;
	}
}
//无头结点的单链表
LinkList reverse(LinkList L) { 
	PNode p,q;
	p=L;
	L=NULL;
	q->link=NULL;
	while(p!=NULL) {
		q=p;
		p=p->link;
		q->link=L;
		L=q;
	}
	return q; //自己加的,答案没有,离谱+1
}

在这里插入图片描述

//采用带表头单元的单链表
LinkList delete_same(LinkList llist) {
	PNode p,q;
	LinkList r;
	if (llist==NULL) return NULL;
	p = llist;
	while(p->next!=NULL) {
		q=p->next;
		while(q->next!=NULL))
			if(p->next->info == q->next->info) {
				r = q ->next;
				q ->next = q->next->next;
				free(r);
			} else {
				q  = q->next;
			}
		p = p->next;
	}
	return 1; //???返回1没看懂,有时间再琢磨,离谱+1
}

编写一算法,删除单链表中所有值为x的无素

//采用带表头单元的单链表
int delete_x(LinkList llist, DataType x) {
	PNode p,q;
	if((llist==NULL) || (llist->next==NULL)) return 0;
	p = llist;
	while(p ->next !=NULL) {
		if(p ->next ->info== x ) {
			q =p ->next;
			p ->next= p ->next ->next;
			free(q);
		}
	}
	else {
		p  = p ->next;
	}
	return 1;
}

在这里插入图片描述

void insertPost_link( LinkList llist, PNode p,  DataType x) {
	PNode q = (Pnode)malloc(sizeof(struct Node));
	if  (q == NULL) {
		printf("Out of space!! \n");
	} else {
		q->info=x;
		if  ( p == NULL)  {
			q->link  = llist;
			llist = q;
		} else {
			q -> link = p -> link ;
			p->link  = q;
		}
	}
}

以下是循环链表作业:

1:简述以下算法的功能

void BB(Lnode *s, Lnode *q){
    p=s;
    while (p->next!=q) p=p->next;
    p->next =s;
}
 void AA(Lnode *pa, Lnode *pb){
     BB (pa, pb);
     BB (pb, pa);
}

其中, pa, pb两个指针指向某个单循环链表中的某两个单元。

答案:
如果L长度不小于2,将L的首节点变成尾结点。将单循环链表拆成两个单循环链表。

3、栈,队列

栈:后进先出
队列:先进先出

字符串

顺序表示:

structSeqString {/* 顺序串的类型*/
	int MAXNUM;/* 串允许的最大字符个数*/
	int n; /* 串的长度,n≤MAXNUM */ 
	char *c;
};
typedef  structSeqString  *PSeqString;

链接表示:

struct StrNode; /* 链串的结点 */
typedef struct StrNode *PStrNode;    /* 结点指针类型 */
struct StrNode  {/* 链串的结点结构 */
	char c;
	PStrNode link;
};
typedef  struct  StrNode  *LinkString; /* 链串的类型 */
1、kmp算法

详见 KMP算法

在这里插入图片描述

1、​结点个数计算

例子:
在这里插入图片描述
PS:树的度:树内各结点的度的最大值

这里求叶子结点个数(即度为0,没有子结点),如果换成问度为n的结点个数,一样的做法。

  • 等式左边:所有结点个数和 -1,即为边的个数
    (除了根结点,其他结点都有往父亲连的边,相当于自底向上计算)
  • 等式右边:每个结点×度数 之和,还是边的个数
    (相当于自上而下计算)
  • 解等式就可以算出任何结点的个数
2、​树的三种表示方法

这部分需要知道三种表示方法是什么样的

  • 父亲数组表示法:
struct ParTreeNode{ 
	DataType info; //结点数据信息
	int parent; //父亲的下标
} 

按照某种遍历顺序,依次存放各结点,例如按照前序顺序:

  • 子表表示法:
    一棵树 = 结点表 + 子表
    • 子表:按从左至右的顺序组成1个单链表;
    • 结点表:包含n个元素,每个元素结构为:
      • 结点信息和该结点的子表头指针;
struct EdgeNode { //子表中元素的类型
	int nodePosition;
	struct EdgeNode * link;
}
struct ChiTreeNode { //结点表中元素的类型
	DataType info;
	struct EdgeNode * children;
}
struct ChiTree { //树的类型(顺序表结构)
	int MaxNum;
	int root; //树根在数组中的下标
	int n;
	struct ChiTreeNode * nodelist; //数组, 结点表
}
typedef struct ChiTree * PChiTree; //树指针类型
  • 长子-兄弟表示法:
    靠 左孩子结点(lchild) 和 右兄弟结点(rsibling) 确定结构
struct CSNode; //长子--兄弟表示法,结点结构
typedef  struct CSNode * PCSNode;
struct CSNode {
	Datatype info;
	PCSNode lchild; //长子指针
	PCSNode rsibling; //右兄弟指针
}
3、树的遍历

知道即可,主要考察二叉树遍历

  • 深度优先遍历

    • 先根(先序)遍历(根-左-右)
    • 中根(中序)遍历(左-根-右)
    • 后根(后序)遍历(左-右-根)
  • 广度优先遍历

字典

1、顺序检索,二分检索

顺序检索不用说了,按顺序一个个查。

二分检索:有序的顺序表

  1. 将key与待查找表中间位置的关键码比较
  2. 若相等,则找到
    否则,中间位置的某一侧作为新待查找表

例子:
在这里插入图片描述
注意:最后一次相等的比较也算一次

  • 法1:
    第1次比较:512, 第2次比较:703
    第3次比较:653, 第4次比较:612
  • 法2:
    第1次比较:509, 第2次比较:677,
    第3次比较:612
2、顺序检索,​二分检索的查找长度

ASL(Average Search Length),即平均查找长度,在查找运算中,由于所费时间在关键字的比较上,所以把平均需要和待查找值比较的关键字次数称为平均查找长度。
在这里插入图片描述

  • 顺序查找:

  • 二分查找:

    最大检索长度 j和元素数目n之间关系:

    • 2j-1-1< n ≤2 j-1, 即 log2(n+1) ≤ j < log2(n+1)+1
      所以 j = log2(n+1)
3、散列,碰撞,除余法

散列:

碰撞:

散列函数:

除余法:

例子:
在这里插入图片描述
在这里插入图片描述
m=16*2=32
p=31
散列函数 h(key)=key%p

4、​线性勘察法(开地址法处理碰撞)

例子:
在这里插入图片描述

已知n个关键码具有相同的散列值d,若采用线性探查法解决碰撞,则在散列这n个关键码的过程中,共将要发生 n(n-1)/2 次碰撞

5、拉链法解决碰撞

例子:

平均查找长度ASL:

二叉排序树

重点:

  • 二叉排序树概念
  • 重要性质(中序递增)
  • 构造二叉排序树(插入新节点过程),检索,删除
  • 二叉排序树检索长度,平均检索长度

具体查看 二叉搜索树

作业题:
在这里插入图片描述

在这里插入图片描述
算法思想:在二叉排序树中,查找一个元素,总共比较n次,该结点的层数就是n-1层 (约定根为第0层)
(因为当前层不匹配就直接跳到下一层子结点比较)

int search_layer(PBinSearchTree ptree, PBinSearchNode pnode) { //查找pnode结点
	PBinSearchNode p = *ptree;
	int layer=0; //设根为第0层
	while ( p != NULL) {
		if(p->key == pnode->key) //相等,则找到
			return layer;
		if(p->key > pnode->key) {
			p = p->llink;     //已比较1次
			layer++;
		} else {
			p = p->rlink;     //已比较1次
			layer++;
		}
	}
	return -1; //未找到或者是空树
}

在这里插入图片描述
算法思想:
从根出发,沿着p, q的公共祖先前进:

  • 当p, q小于当前结点,沿着当前结点的左指针前进;
  • 当p, q大于当前结点,沿着当前结点的右指针前进;
  • 当第1次遇到1个结点X的值介于p, q的值之间、或者等于其中1个,则X就是p, q的最近公共祖先。
PBinSearchNode FindLowestAncestor
(PBinSearchTree ptree, PBinSearchNode p,
 PBinSearchNode q) { //查找p, q的最近公共祖先
	PBinSearchNode X = *ptree;
	while ( X != NULL) {
		if(X->key > p->key && X->key > q->key)
			X = X->llink; //X的值比p,q都大
		else if(X->key < p->key && X->key < q->key)
			X = X->rlink; //X的值比p,q都小
		else
			return X;
	}
	return -1; //未找到
}

平衡二叉排序树

重点:

  • 平衡因子
  • 四种失衡模式
  • 找出最小不平衡子树
  • 失衡调整(例题

具体参考 平衡二叉树

AVL树:每个结点的左、右子树高度之差的绝对值不超过1.

结点的平衡因子 = 右子树高度 – 左子树高度

例子:

在这里插入图片描述

在这里插入图片描述

(1)

(2)

PBinSearchNode p= t->rlink;
t->rlink = p->llink;
p->llink = t;
t->bf=0;
p->bf=0;
t = p;

1、基本概念,度和边的关系
  • 简单图:无重边和自环

  • 完全图:任意两个顶点之间,都有1条边

    • 若G是有向图,则e=n(n-1)
    • 若G是无向图,则e=n(n-1)/2
  • (顶点间)邻接、(顶点与边)关联

  • 顶点的度D(V),(有向图顶点的)入度和出度:

    • 有向图:
      - V的入度:以V为终点的边数
      - V的出度:以V为起点的边数
      - V的度:入度 + 出度
    • 无向图:
      - V的度:V的关联边的个数
      - 边数 e = 0.5 × ∑(所有顶点的度)
  • 回路:起点与终点相同的一条路径;
    简单路径:只有起点和终点可以相同,即内部无回路;
    简单回路:起点和终点相同的简单路径;

  • (有向图中的)有根图:
    有向图G=(V,E)中,
    - 若存在一个顶点V,可以达到所有顶点,则称V是图的根;
    - 1个有向图的根,可不唯一;

  • (无向图中的)连通、连通图

    • Vi与Vk连通:Vi与Vk之间至少存在1条路径;
    • 连通图:图中任意两个顶点都连通;
  • (无向图的)连通分量:极大(最大)连通子图G*;
    - 极大:向G*中增加原图G中的任意顶点或边,新子图不连通;
    - 若G不连通,则其连通分量> 1个;

  • (有向图中的)强连通图、强连通分量

    • 强连通图:任意两个顶点Vi与Vk, 从Vi到Vk 、从Vk到Vi都有路径;
    • 强连通分量:有向图G的最大强连通子图;
  • 带权图:每1条边都被赋予一定权值;
    带权路径长度:路径上,所有边的权值之和;
    网络:带权的连通图;

2、邻接矩阵(带权不带权),计算度(出入度),邻接关系
  • 不带权:

    • 无向图:对称矩阵

      • 顶点Vi的度 = 下标为 i 的行 or 列中,元素之和
    • 有向图:不一定为对称矩阵

      • Vi 的出度 = 下标为i的行, 元素之和
      • Vi 的入度 = 下标为i的列, 元素之和
  • 带权:ω为权值

    • 无向带权图:对称矩阵
      • 顶点Vi的度 = 下标为 i 的行 or 列中,非0非∞的个数
    • 有向带权图:不一定为对称矩阵
    • 顶点Vi出度 = i 行中非0非∞的个数;
    • 顶点Vi入度 = i 列中非0非∞的个数;
typedef  char  VexType; //设置顶点类型为字符型
typedef  float  AdjType; //设置关系矩阵元素为float型
typedef struct {
	int vexNum, arcNum; //顶点个数,边数
	VexType vexs[vn]; //一维数组:顶点表vexs
	AdjType  arcs[vn][vn]; //二维数组:邻接矩阵arcs
} GraphMatrix; //GraphMatrix:图的类型
3、邻接表(两个结点是否连接),计算度,删除边,边反向

邻接(链)表表示:

  • 无向图 = 顶点表 + 边表

  • 有向图 = 顶点表 + 出边表 (出边表计算入度)

  • 有向图 = 顶点表 + 入边表 (入边表计算出度)

删除边:单链表删除一个结点,如果为第一个结点,还要修改顺序数组中的数值

边反向:在原来的单链表删除一条边,在反向的单链表增加一条边(加在尾部)

struct EdgeNode; //边表中的结点类型
typedef struct EdgeNode * PEdgeNode;
typedef struct EdgeNode * EdgeList;
struct EdgeNode { // 边表中的结点结构
	int ajdVex; //邻接顶点的下标
	AdjType weight;
	PEdgeNode nextEdge; //指向下1条(出、入)边
}; // 边表中,1个结点代表1条(出、入)边

typedef struct {
	VexType  vertex; //顶点信息
	EdgeList  edgelist; //边表头指针
} VexNode; //VexNode:顶点表中元素类型
typedef struct {
	VexNode  vexs[VN]; //顶点表(1维数组)
	int  vexNum, arcNum; //顶点数, 边数
} GraphList; //GraphList:顶点表(图)的结构类型
4、图的遍历(dfs,bfs)序列,两种生成树,最小生成树两种方法

图的遍历(dfs和bfs)就不说了,基础。

具体查看 最小生成树

作业题:
1、已知一个无向图G=(V, E),其中V={a, b, c, d, e},E={(a,b), (a, c), (a, d), (c, d), (b, e)},从a开始,深度优先遍历序列、广度优先遍历序列分别是 ?
深度优先遍历序列:a b e c d
广度优先遍历序列:a b c d e

2.、P327,对于图9.23,请给出其深度优先、广度优先遍历序列。
在这里插入图片描述
深度优先遍历序列:v0 v1 v4 v6 v8 v7 v2 v3 v5
广度优先遍历序列:v0 v1 v2 v3 v4 v5 v6 v7 v8

3.、P327,对于图9.26, 请给出其深度优先、广度优先遍历序列。
在这里插入图片描述
深度优先遍历序列:v0 v1 v3 v2 v4 v5 v6 v7
广度优先遍历序列:v0 v1 v2 v3 v4 v5 v6 v7

在这里插入图片描述
(1) 邻接矩阵arcs中,非0元素个数的1/2.
(2) 若arcs[i][j]或arcs[j][i]不等于0,则vi与vj有边相连;
(3) vi的度:arcs中下标为i的行或列中1的个数。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


在这里插入图片描述
出边表表示:

Struct EdgeNode;
typedef struct EdgeNode *PEdgeNode;
		typedef struct EdgeNode *EdgeList;
			Struct EdgeNode { //边表结点结构
		int endVex;
		int weight;
		PEdgeNode nextEdge;
	};
typedef struct { //顶点表元素结构
	char  vertex;
	EdgeList  edgelist;
} VexNode;
typedef struct { //图结构
	VexNode  vexs[VN];
	int  vexNum, arcNum;
} GraphList;
int is_end(GraphList g, int k) {
	EdgeList p;
	int i;
	for(i=0; i<g.vexNum; i++) {
		p=g.vexs[i].edgelist;  //p取得边表头指针
		while(p!=Null) {
			if(p->endvex == k)   return1;
			p = p->nextedge;
		}
	}
	return 0;
}

邻接矩阵表示:

typedef struct {
	int vexNum, arcNum;
	char vexs[vn];
	float  arcs[vn][vn];
} GraphMatrix;   //图结构
int is_end(GraphMatrix g, char x) {
	int i, k;
	for(i=0; i<g.vexNum; i++)  //寻找字符x的下标k
		if( g.vexs[i]==x )  {
			k=i;
			break;
		}
	for(i=0; i<g.vexNum; i++) //判断arcs中第k列是否有1
		if(g.arcs[i][k] ==1)   return 1;
	return 0
}
5、最短路径(distance数组),给出数组,求出最短路径

具体参考 最短路径
不过考试只要求Dijkstra算法:

基于贪心策略的思想,算法是按路径长度从小到大的顺序一步一步并入来求取,用来解决单源点到其余顶点的最短路径问题。
时间复杂度O(N^2),堆优化后时间复杂度O(nlogn)。

即:从剩余路径中找最短的路径,然后更新最短路径。
d[ i ] = min { d[ j ] + (j -> i 边权值) | e=(j,i)∈E}

下面直接看作业题理解
作业题:
在这里插入图片描述
注意:写出完整的dist数组变化过程;并列出:最短路径(即顶点序列)、各最短路径长度

6、拓扑排序概念和序列

具体参考 拓扑排序

作业题:

采用栈作为辅助空间,计算1个拓扑序列。

老师给的答案:

7、关键路径概念,计算过程

具体参考 关键路径

作业题:

排序

重点内容

  • 插入排序,选择排序,冒泡排序,交换排序重点
  • 知道希尔操作过程
  • 快排第一趟快排结果()
  • 堆排序要会应用(完全二叉树从左到右,整个过程
  • 知道基数排序和归并

具体参考 排序汇总

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值