考研计算机874数据结构知识整理 Apare_xzc

考研计算机874数据结构知识整理Apare_xzc

for zcy勇哥

2020.11.17


一、题目类型

10道填空题
4道综合题
2道算法题(出自历年期末考试,主要考链表和二叉树)

二、综合题的考点

  1. 二叉树的遍历(给出先序中序还原二叉树,求后序)
  2. 线索二叉树(画出)
  3. 排序算法的比较(最好最坏时间空间复杂度,稳定性)
  4. 哈夫曼编码(给定字母出现概率,生成哈夫曼树,求每个字母的编码,以及带权路径总长度WPL)
  5. 最小生成树(Prim, Kruskal)
  6. 堆排序相关(初始建堆的结果,每一趟的结果)
  7. 哈希表(给出待散列的序列,除留取余法,链地址法处理冲突,求出每个元素的散列地址,求平均查找长度)
  8. 最短路径(Dijkstra)
  9. 折半查找(画出判定树,求平均查找长度(成功/失败),求查找某个值得过程)
  10. 图的综合题(给一个图,求邻接表,求深度优先遍历的结果,根据Prim构造最小生成树)
  11. 二叉排序树(给一个线性表序列,插入到空的二叉排序树中,求出其平均查找长度)

三、算法编程题

2020年:统计字符串中单词出现的个数(直接C++map,java Hashmap, 或者用有序链表维护)
2019年:求二叉树的宽度,删除有序链表在(mink,maxk)范围的结点
2018年:在用双向链表实现的有序表中检索具有关键字key的结点, 二叉排序树的查找、插入(非递归)
2017年:有序链表中插入元素,二叉排序树的查找、插入(非递归)
2016年:求链表中结点为值为偶数的结点之和,求二叉树叶子结点值之和
2015,2014年:求链表结点值能被5整除/能被2整除的个数(链表的遍历)
2013年:送分水题,输入一行字符,统计其中数字,字母,空格和其它字符的个数。

四、填空选择考点

广义表
二叉树的遍历
图的广度优先遍历
哈希表
归并排序的趟数
中缀,后缀表达式,表达式树
单链表的插入,删除,遍历
循环队列的实现,栈的实现(top,head,tail如何赋值)
拓扑排序
二分查找,插入二叉排序树,插入堆的复杂度O(log2n)
有向图、无向图的最大边数,顶点度数
顺序存储,链式存储
二叉树叶子结点的个数
可能的出栈顺序
初始堆
快排时间复杂度,第一次划分后的结果


算法题详解:

1. [2020年真题]统计字符串中单词出现的个数,按照字典序输出。

可以用有序链表维护。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct ListNode{
     
      //链表结点的定义
	int cnt;  //这个单词出现的次数
	char word[20]; //记录单词
	struct ListNode * next;
}ListNode;
int main(void) {
     
     
	char str[20];
	ListNode * head = (ListNode*)malloc(sizeof(ListNode)); //头结点 
	head->next = NULL;
	ListNode * p = head;
	while(scanf("%s",str)!=EOF) {
     
       
		p = head;
		int flag = 0;
		while(p->next) {
     
       //从前往后遍历链表
			if(strcmp(p->next->word,str)==0) {
     
     
				p->next->cnt += 1; 
				flag = 1;
				break;
			} 
			else if(strcmp(p->next->word,str)>0) break;
			else p = p->next;
		} 
		if(!flag) {
     
     
			p = head;
			while(p->next&&strcmp(p->next->word,str)<0)  //找到插入的位置
				p = p->next;
			ListNode * tmp = (ListNode*)malloc(sizeof(ListNode));
			tmp->cnt = 1;
			strcpy(tmp->word,str);
			tmp->next = p->next;
			p->next = tmp;
		}
	}
	p = head;
	while(p->next) {
     
     
		printf("%s\t%d\n",p->next->word,p->next->cnt);
		p = p->next;
	}	
	return 0;
} 

在这里插入图片描述


2. [2019年真题]求二叉树的宽度

维护一个CurCnt变量,记录上一层在队列中的结点数。当CurCnt为0时,说明此时队列中都是这一层的。于是用Q.size()更新答案
核心代码:

int GetWidthOfBinaryTree(TreeNode * root) {
     
     
	if(!root) return 0;
	std::queue<TreeNode*> Q;
	Q.push(root);
	int CurCnt = 1,MaxWidth=0;
	while(!Q.empty()) {
     
     
		TreeNode * tp = Q.front(); Q.pop();
		if(tp->lson) Q.push(tp->lson);
		if(tp->rson) Q.push(tp->rson);
		if(--CurCnt==0) {
     
     
			MaxWidth = max(MaxWidth,(int)Q.size());
			CurCnt = Q.size();
		}
	} 
	return MaxWidth;
}

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <queue>
#define maxn 100
#define max(a,b) (a>b?a:b)
using namespace std;
struct TreeNode{
     
     
	char val;
	struct TreeNode * lson;
	struct TreeNode * rson;
};
char sequence[maxn] = "ABD#G##EH##I##C#FJ###";
TreeNode * buildTree(char * str,int& x) {
     
     
	if(str[x]=='#') {
     
     
		x++;
		return NULL;
	}
	TreeNode * pNode = (TreeNode*)malloc(sizeof(TreeNode));
	pNode->val = str[x++];
	pNode->lson = buildTree(str,x);
	pNode->rson = buildTree(str,x);
	return pNode;
} 

int GetWidthOfBinaryTree(TreeNode * root) {
     
     
	if(!root) return 0;
	std::queue<TreeNode*> Q;
	Q.push(root);
	int CurCnt = 1,MaxWidth=0;
	while(!Q.empty()) {
     
     
		TreeNode * tp = Q.front(); Q.pop();
		if(tp->lson) Q.push(tp->lson);
		if(tp->rson) Q.push(tp->rson);
		if(--CurCnt==0) {
     
     
			MaxWidth = max(MaxWidth,(int)Q.size());
			CurCnt = Q.size();
		}
	} 
	return MaxWidth;
}
int main(void) {
     
     
	int idx = 0;
	TreeNode * root = buildTree(sequence,idx);
	printf("二叉树的宽度为:%d\n",GetWidthOfBinaryTree(root)); 
	
	return 0;
}

3. [2019年真题]删除有序链表在(mink,maxk)范围的结点

核心代码如下:

void DeleteNode(ListNode * head,int mink,int maxk) {
     
      //head为不记录数据的头结点指针
	ListNode * p = head;
	while(p->next) {
     
     
		if(p->next->val>mink && p->next->val<maxk) {
     
     
			ListNode * tmp = p->next;
			p->next = tmp->next;
			free(tmp);
		}
		else p = p->next;
	}
}

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

struct ListNode{
     
     
	int val;
	struct ListNode * next;
};
void InsertNode(ListNode * head,int v) {
     
     
	ListNode * p = head;
	while(p->next&&p->next->val<=v) p = p->next;
	ListNode * tmp = (ListNode*)malloc(sizeof(ListNode));
	tmp->val = v;
	tmp->next = p->next;
	p->next = tmp;
}
void ShowList(ListNode * p) {
     
     
	while(p) printf("%d ",p->val),p = p->next;
	printf("\n");
}
void DeleteNode(ListNode * head,int mink,int maxk) {
     
     
	ListNode * p = head;
	while(p->next) {
     
     
		if(p->next->val>mink && p->next->val<maxk) {
     
     
			ListNode * tmp = p->next;
			p->next = tmp->next;
			free(tmp);
		}
		else p = p->next;
	}
}

int main(void) {
     
     
	ListNode * head = (ListNode*)malloc(sizeof(ListNode));
	head->next = NULL;
	InsertNode(head,5);
	InsertNode(head,5);
	InsertNode(head,6);
	InsertNode(head,1);
	InsertNode(head,4);
	InsertNode(head,7);
	InsertNode(head,2);
	InsertNode(head,3);
	InsertNode(head,9);
	InsertNode(head,0);
	ShowList(head->next);
	DeleteNode(head,2,6);
	ShowList(head->next);
	
	
	return 0;
} 

4. [2013年真题]输入一行字符,统计数字,英文字母,空格,其它字符的个数
#include <stdio.h>
#include <algorithm> 
char str[200];
int main(void) {
     
     
	int space=0,letter=0,digit=0,other=0;
	gets(str); //std::cin.getline(str,200)    <iostream>
	for(int i=0;str[i];++i) {
     
     
		if(str[i]==' ') space++;
		else if(isdigit(str[i])) digit++;
		else if(isalpha(str[i])) letter++;
		else other++;
	}
	printf("空格:%d个\n",space);
	printf("字母:%d个\n",letter);
	printf("数字:%d个\n",digit);
	printf("其它:%d个\n",other);
	return 0;
} 

在这里插入图片描述


六、综合题要点

1. 堆排序,建堆,每一趟的过程

[2018年第13题] 从空堆开始插入{64,52,12…} 每趟的结果
#include <stdio.h>
int a[100];
int b[] = {
     
     0,64,52,12,48,45,26};
//int b[] = {0,1,4,5,2,3,8,100,6,7,4,4,3}; 
//小顶堆 
void AdjustToHeap(int * a,int n) {
     
     
	for(int i=n/2;i>=1;--i) {
     
     
		int j = i,tmp = a[j];
		while(j*2<=n) {
     
     
			int son = j*2;
			if(son+1<=n&&a[son+1]<a[son]) son = son+1;
			if(a[son]<tmp) a[j] = a[son], j = son;
			else break;
		}
		a[j] = tmp;
	}
}
int main(void) {
     
     
	int n = 6;
//	n = 12;
	for(int i=1;i<=n;++i) {
     
     
		a[i] = b[i];
		AdjustToHeap(a,i);
		for(int j=1;j<=i;++j)
			printf("%d ",a[j]);printf("\n");
	} 
	
	return 0;
} 

答案:

64
52 64
12 64 52
12 48 52 64
12 45 52 64 48
12 45 26 64 48 52

在这里插入图片描述

堆排序的实现:
#include <stdio.h>
const int maxn = 200;
int a[maxn] = {
     
     0,1,4,5,2,3,8,100,6,7,4,4,3};
//int a[maxn] = {0,8,7,4,2,5,1};
//下表都从1开始 
//从小到大排序,维护一个大顶堆 
void AdjustOnce(int * a,int pos,int n) {
     
     
	int tmp = a[pos];
	int j = pos;
	while(j*2<=n) {
     
     
		int son = j*2;
		if(son+1<=n&&a[son+1]>a[son]) son = son+1;
		if(a[son]>tmp) a[j] = a[son], j = son;
		else break;
	}
	a[j] = tmp;
} 
void toHeap(int *a,int n) {
     
     
	for(int i=n/2;i>=1;--i) {
     
     
		AdjustOnce(a,i,n);
	}
}
void HeapSort(int *a,int n) {
     
      //a[1]到a[n]排序 
	toHeap(a,n);
	int m = n;
	for(int i=1;i<n;++i) {
     
     
		int tmp = a[m]; a[m] = a[1]; a[1] = tmp; //把堆顶的最大元素换到最后一个位置
		AdjustOnce(a,1,--m); 
	} 
	for(int i=1;i<=n;++i)
		printf("%d ",a[i]);printf("\n");
}


int main(void) {
     
     
	int n = 12;
//	n = 6;
//	scanf("%d",&n);
//	for(int i=1;i<=n;++i)
//		scanf("%d",&a[i]);
	HeapSort(a,n);
	
	return 0;
} 

在这里插入图片描述


2. Huffman数

[2016年,第13题] abcdefgh的概率为[9,16,22,18,3,15,12,5]写出哈夫曼编码
#include <stdio.h>
#include <queue>
const int maxn = 100;
char str[] = "abcdefgh";
int Lson[maxn];
int Rson[maxn];
bool vis[maxn];
//int a[maxn] = {5,29,7,8,14,23,3,11};
//int a[maxn] = {10,25,20,30,15}; 
//int a[maxn] = {3,7,8,2,6,10,14};
int a[maxn] = {
     
     9,16,22,18,3,15,12,5}; 
char record[maxn];
void dfs(int rt,int x,int& wpl) {
     
     
	if(rt==-1) return;
	if(Lson[rt]==-1 && Rson[rt]==-1) {
     
      //叶子结点 
		wpl += a[rt]*x;
		record[x] = '\0';
		printf("%c: %s\n",str[rt],record);
		return; 
	}
	if(Lson[rt]!=-1) {
     
     
		record[x] = '0';
		dfs(Lson[rt],x+1,wpl);
	}
	if(Rson[rt]!=-1) {
     
     
		record[x] = '1';
		dfs(Rson[rt],x+1,wpl);
	}
}
void getHuffmanCommon() {
     
     
	int n = 8;
	int m = n;
	for(int i=0;i<n;++i)
		vis[i] = false, Lson[i] = -1, Rson[i] = -1;	
	for(int i=1;i<n;++i) {
     
     
		int minId1 = -1, minId2 = -1;
		for(int j=0;j<m;++j) {
     
     
			if(!vis[j]&&(minId1==-1||a[j]<a[minId1])) minId1 = j;
		}
		vis[minId1] = true;
		for(int j=0;j<m;++j) {
     
     
			if(!vis[j]&&(minId2==-1||a[j]<a[minId2])) minId2 = j;
		}
		vis[minId2] = true;
		a[m] = a[minId1]+a[minId2];
		Lson[m] = minId1;
		Rson[m] = minId2;
		m++;
	}
	int WPL = 0; 
	dfs(m-1,0,WPL);
	printf("带权路径长度WPL为:%d\n",WPL);
}
int main(void) {
     
     
//	getHuffmanUsingHeap();
	getHuffmanCommon();
	
	return 0;
} 

在这里插入图片描述

拓展:用堆优化Huffman

void getHuffmanUsingHeap() {
     
     
	int n = 8,m = n;
	using std::pair;
	using std::vector;
	using std::priority_queue; 
	using std::greater;
	using std::make_pair;
	priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > Q;
	for(int i=0;i<n;++i)
		vis[i] = false, Lson[i] = -1, Rson[i] = -1, Q.push(make_pair(a[i],i));
	for(int i=1;i<n;++i) {
     
     	
		int minId1 = Q.top().second; Q.pop();
		int minId2 = Q.top().second; Q.pop();
		a[m] = a[minId1]+a[minId2];
		Lson[m] = minId1;
		Rson[m] = minId2;
		Q.push(make_pair(a[m],m));
		m++;
	}
	int WPL = 0;
	dfs(m-1,0,WPL);
	for(int i=0;i<m;++i)
	{
     
     
		printf("%2d %d %d\n",a[i],Lson[i],Rson[i]);
	}
	printf("带权路径长度WPL为:%d\n",WPL);
}

最小生成树

  1. Kruskal求MST
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
const int maxn = 200;
struct Edge{
     
     
	int u,v,dis;
	bool operator < (const Edge& rhs)const{
     
     
		return dis < rhs.dis;
	}
}edge[maxn];
struct UFSet{
     
     
	int father[maxn];
	void init() {
     
     
		for(int i=0;i<maxn;++i)
			father[i] = i;
	}
	int getFather(int x) {
     
     
		return x==father[x]?x:father[x]=getFather(father[x]);
	}
	bool join(int x,int y) {
     
     
		int fx = getFather(x), fy = getFather(y);
		if(fx==fy) return false;
		father[fy] = fx;
		return true;
	} 
}ufset;
int main(void) {
     
     
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;++i)
		scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].dis);
	std::sort(edge,edge+n);
	int cnt = 0;
	int ans = 0;
	ufset.init();
	for(int i=0;i<n&&cnt<n-1;++i) {
     
     
		if(ufset.join(edge[i].u,edge[i].v)) {
     
     
			cnt += 1; 
			ans += edge[i].dis;
		}
	}
	printf("%d\n",ans);	
	return 0;
} 
/*
5 
1 2 1
2 3 2
3 4 4
4 5 8
5 1 16


*/

未完待续…

猜你喜欢

转载自blog.csdn.net/qq_40531479/article/details/109744268