计算机考研复试上机07

14、数据结构

1)二叉树

1.常用操作
struct TreeNode{
	int data;
	TreeNode *leftChild;
	TreeNode *rightChild;
}; 
//前序遍历
void PreOrder(TreeNode *root){
	if(root == NULL) return;
	visit(root->data);
	PreOrder(root->leftChild);
	PreOrder(root->rightChild);
	return;
} 
//层序遍历 
void levelOrder(TreeNode *root){
	queue<TreeNode*> myQueue;
	if(root != NULL) myQueue.push(root);
	while(!myQueue.empty()){
		TreeNode *current = myQueue.front();
		myQueue.pop();
		visit(current->data);
		if(current->leftChild != NULL)
			myQueue.push(current->leftChild);
		if(current->rightChild != NULL)
			myQueue.push(current->rightChild);
	}
}
2.二叉树遍历(清华大学复试上机题)

题目描述:

编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一棵二叉树(以指针方式存储)。例如,先序遍历字符串 ABC##DE#G##F###,其中“#”表示空格,空格字符代表空树。建立这棵二叉树后,再对二叉树进行中序遍历,输出遍历结果。

#include <bits/stdc++.h>
using namespace std;

struct TreeNode{
	char data;
	TreeNode *leftChild;
	TreeNode *rightChild;
	TreeNode(char c): data(c), leftChild(NULL), rightChild(NULL){}
}; 

TreeNode *Build(int &position, string str){
	char c = str[position++];
	if(c == '#') return NULL;
	TreeNode *root = new TreeNode(c);
	root->leftChild = Build(position,str);
	root->rightChild = Build(position, str);
	return root;
}

void InOrder(TreeNode *root){
	if(root == NULL) return;
	InOrder(root->leftChild);
	cout<<root->data<<" ";
	InOrder(root->rightChild);
	return;
}

int main(){
	string str;
	while(cin>>str){
		int position = 0;
		TreeNode *root = Build(position, str);
		InOrder(root);
	}
	cout<<endl;
	return 0; 
}

2)二叉排序树

1.二叉排序树(华中科技大学复试上机题)

题目描述:

二叉排序树也称二叉查找树。它可以是一棵空树,也可以是一棵具有如下特性的非空二叉树:1. 若左子树非空,则左子树上所有结点的关键字值均不大于根结点的关键字值。2. 若右子树非空,则右子树上所有结点的关键字值均不小于根结点的关键字值。3. 左、右子树本身也是一棵二叉排序树。 现在给你 N 个关键字值各不相同的结点,要求你按顺序将它们插入一个初始为空树的二叉排序树,每次插入成功后,求相应父结点的关键字值,若没有父结点,则输出-1。

#include <bits/stdc++.h>
using namespace std;

struct TreeNode{
	int data;
	TreeNode *leftChild;
	TreeNode *rightChild;
	TreeNode(int x): data(x),leftChild(NULL),rightChild(NULL){}
};

TreeNode *insert(TreeNode *root,int x,int father){
	if(root == NULL){
		root = new TreeNode(x);
		cout<<father<<endl;
	}else if(x < root->data){
		root->leftChild = insert(root->leftChild,x,root->data);
	}else{
		root->rightChild = insert(root->rightChild,x,root->data);
	}
	return root;
}

int main(){
	int n;
	while(cin>>n){
		TreeNode *root = NULL;
		for(int i = 0;i < n;i++){
			int x;
			cin>>x;
			root = insert(root,x,-1);
		}
	}
	
	return 0; 
}

3)优先队列

1.常用操作
#include <bits/stdc++.h>
using namespace std;

int main(){
	priority_queue<int> queue;
	cout<<queue.size()<<endl;
	queue.push(20);
	queue.push(100);
	queue.push(30);
	queue.push(50);
	cout<<queue.top()<<endl;
	cout<<queue.size()<<endl;
	int sum = 0;
	while(!queue.empty()){
		cout<<queue.top()<<endl;
		sum += queue.top();
		queue.pop();
	}
	cout<<sum<<endl;
	
	return 0; 
}
2.哈夫曼树(北京邮电大学复试上机题)

题目描述:

哈夫曼树,第一行输入一个数 n,表示叶结点的个数。需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即 weight,题目需要输出所有结点的值与权值的乘积之和。

#include <bits/stdc++.h>
using namespace std;

int main(){
	int n;
	while(cin>>n){
		priority_queue<int, vector<int>, greater<int> > queue;
		while(n--){
			int x;
			cin>>x;
			queue.push(x); 
		}
		int answer = 0;
		while(1 < queue.size()){
			int a = queue.top();
			queue.pop();
			int b = queue.top();
			queue.pop();
			answer += a + b;
			queue.push(a+b);
		}
		cout<<answer<<endl;
	}
	
	
	return 0; 
}
3.查找第 K 小的数(北京邮电大学复试上机题)

题目描述:

查找一个数组中第 K 小的数,注意同样大小算一样大。例如,在 2, 1, 3, 4, 5, 2 中,第三小的数是3。

#include <bits/stdc++.h>
using namespace std;

int main(){
	int n;
	while(cin>>n){
		priority_queue<int, vector<int>, greater<int> > queue;
		int pre;
		for(int i = 0;i < n;i++){
			cin>>pre;
			queue.push(pre);
		}
		int k;
		cin>>k;
		pre = queue.top();
		for(int i = 1;i < k;i++){
			queue.pop();
			if(pre == queue.top())
				i--;
			pre = queue.top();
		}
		cout<<queue.top()<<endl;
	}
	
	return 0; 
}
4.搬水果(吉林大学复试上机题)

题目描述:

在一个果园里,小明已经将所有的水果打了下来,并按水果的不同种类分成了若干堆,小明决定把所有的水果合成一堆。每一次合并,小明可以把两堆水果合并到一起,消耗的体力等于两堆水果的重量之和。当然,经过 n 1 次合并之后,就变成一堆了。小明在合并水果时总共消耗的体力等于每次合并所耗体力之和。假定每个水果的重量都为 1,并且已知水果的种类数和每种水果的数目,你的任务是设计出合并的次序方案,使小明耗费的体力最少,并输出这个最小的体力耗费值。例如有 3 种水果,数目依次为 1, 2, 9。可以先将 1, 2 堆合并,新堆数目为3,耗费体力为3。然后将新堆与原先的第三堆合并得到更新的堆,耗费体力为 12。所以小明总共耗费的体力为3 + 12 = 15,可以证明 15 是最小的体力耗费值。

#include <bits/stdc++.h>
using namespace std;

int main(){
	int n,t;
	while(cin>>n){
		if(n == 0) break;
		priority_queue<int, vector<int>, greater<int> > queue;
		for(int i = 0;i < n;i++){
			cin>>t;
			queue.push(t);
		}
		int answer = 0;
		while(queue.size() > 1){
			int a = queue.top();
			queue.pop();
			int b = queue.top();
			queue.pop();
			answer += a + b;
			queue.push(a+b); 
		}
		cout<<answer<<endl;
	}
	
	return 0; 
}

4)散列表

1.常用操作
#include <bits/stdc++.h>
using namespace std;

int main(){
	map<string, int> myMap;
	myMap["Emma"] = 67;
	myMap["Benedict"] = 100;
	myMap.insert(pair<string,int>("Bob",72));
	myMap.insert(pair<string,int>("mary",20));
	
	cout<<myMap.size()<<endl;
	cout<<myMap["Bob"]<<endl;
	cout<<myMap.at("mary")<<endl;
	myMap.erase("mary");
	map<string,int>::iterator it;
	for(it = myMap.begin();it != myMap.end();it++){
		cout<<it->first<<endl;
		cout<<it->second<<endl;
	}
	myMap.clear();
	if(myMap.empty()){
		cout<<"myMap is empty"<<endl;
	}else{
		cout<<"myMap is not empty"<<endl;
	}
	it = myMap.find("Bob");
	if(it != myMap.end()){
		cout<<"Bob is found"<<endl;
	}else{
		cout<<"Bob is not found"<<endl;
	}
	
	return 0; 
}
2.魔咒词典(浙江大学复试上机题)

题目描述:

哈利·波特在魔法学校的必修课之一就是学习魔咒。据说魔法世界有100000 种不同的魔咒,波特很难全部记住,但为了对抗强敌,他必须在危急时刻能够调用任何一个需要的魔咒,所以他需要你的帮助。给你一部魔咒词典。当哈利听到一个魔咒时,你的程序必须告诉他那个魔咒的功能;当哈利需要某个功能但不知道该用什么魔咒时,你的程序要替他找到相应的魔咒。如果他要的魔咒不在词典中,那么你的程序就输出“what?”。

#include <bits/stdc++.h>
using namespace std;

int main(){
	map<string,string> dictionary;
	string str;
	while(getline(cin,str)){
		if(str == "@END@") break;
		int pos = str.find("]");
		string key = str.substr(0,pos+1);
		string value = str.substr(pos+2);
		dictionary[key] = value;
		dictionary[value] = key;
	}
		
	int n;
	cin>>n;
	getchar();
	while(n--){
		string key;
		getline(cin,key);
		string answer = dictionary[key];
		if(answer == ""){
			answer = "what?";
		}else if(answer[0] == '['){
			answer = answer.substr(1,answer.size() - 2);
		}
		cout<<answer<<endl;
	}
	return 0; 
}
3.子串计算(北京大学复试上机题)

题目描述:

给出一个 01 字符串(长度不超过 100),求其每个子串出现的次数。

#include <bits/stdc++.h>
using namespace std;

int main(){
	string str;
	while(cin>>str){
		map<string, int> number;
		for(int i = 0;i <= str.size();i++){
			for(int j = 0;j < i;j++){
				string key = str.substr(j,i-j);
				number[key]++; 
			}
		}
		map<string, int>::iterator it;
		for(it = number.begin();it != number.end();it++){
			if(it->second > 1)
				cout<<it->first<<" "<<it->second<<endl;
		}
	} 
	
	
	return 0; 
}

15、图论

1)并查集

1.畅通工程(浙江大学复试上机题)

题目描述:

某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1000;

int father[MAXN];
int height[MAXN];

void initial(int n){
	for(int i = 0;i <= n;i++){
		father[i] = i;
		height[i] = 0;
	}
} 

int find(int x){
	if(x != father[x]){
		father[x] = find(father[x]);
	}
	return father[x];
}

void Union(int x,int y){
	x = find(x);
	y = find(y);
	if(x != y){
		if(height[x] < height[y]) father[x] = y;
		else if(height[y] < height[x]) father[y] = x;
		else{
			father[y] = x;
			height[x]++;
		}
	}
}

int main(){
	int n,m;
	while(cin>>n){
		if(n == 0) break;
		cin>>m;
		initial(n);
		
		while(m--){
			int x,y;
			cin>>x>>y;
			Union(x,y);
		}
		int answer = -1;
		for(int i = 1;i <= n;i++){
			if(find(i) == i) answer++;
		}
		cout<<answer<<endl;
	}
	
	
	return 0; 
}
2.连通图(吉林大学复试上机题)

题目描述:

给定一个无向图和其中的所有边,判断这个图是否所有顶点都是连通的。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1000;

int father[MAXN];
int height[MAXN];

void initial(int n){
	for(int i = 0;i <= n;i++){
		father[i] = i;
		height[i] = 0;
	}
} 

int find(int x){
	if(x != father[x]){
		father[x] = find(father[x]);
	}
	return father[x];
}

void Union(int x,int y){
	x = find(x);
	y = find(y);
	if(x != y){
		if(height[x] < height[y]) father[x] = y;
		else if(height[y] < height[x]) father[y] = x;
		else{
			father[y] = x;
			height[x]++;
		}
	}
}

int main(){
	int n,m;
	while(cin>>n){
		if(n == 0) break;
		cin>>m;
		initial(n);
		
		while(m--){
			int x,y;
			cin>>x>>y;
			Union(x,y);
		}
		int answer = 0;
		for(int i = 1;i <= n;i++){
			if(find(i) == i) answer++;
		}
		if(answer == 1) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	
	
	return 0; 
}

2)最小生成树

1.还是畅通工程(浙江大学复试上机题)

题目描述:

某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1000;


struct Edge{
	int from;
	int to;
	int length;
	bool operator< (const Edge& e) const{
		return length < e.length;
	}
};

Edge edge[MAXN * MAXN];
int father[MAXN];
int height[MAXN];

void initial(int n){
	for(int i = 0;i <= n;i++){
		father[i] = i;
		height[i] = 0;
	}
} 

int find(int x){
	if(x != father[x]){
		father[x] = find(father[x]);
	}
	return father[x];
}

void Union(int x,int y){
	x = find(x);
	y = find(y);
	if(x != y){
		if(height[x] < height[y]) father[x] = y;
		else if(height[y] < height[x]) father[y] = x;
		else{
			father[y] = x;
			height[x]++;
		}
	}
}

int Kruskal(int n,int edgeNumber){
	initial(n);
	sort(edge, edge + edgeNumber);
	int sum = 0;
	for(int i = 0;i < edgeNumber;i++){
		Edge current = edge[i];
		if(find(current.from) != find(current.to)){
			Union(current.from, current.to);
			sum += current.length;
		}
	}
	return sum;
}

int main(){
	int n,m;
	while(cin>>n){
		if(n == 0) break;
		
		int edgeNumber = n * (n-1) / 2;
		for(int i = 0;i < edgeNumber;i++){
			cin>>edge[i].from>>edge[i].to>>edge[i].length;
		}
		int answer = Kruskal(n,edgeNumber);
		cout<<answer<<endl;
	}
	
	
	return 0; 
}

3)最短路径

1.畅通工程续(浙江大学复试上机题)

题目描述:

某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离短很多。这让行人很困扰。 现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 200;
const int INF = INT_MAX;

struct Edge{
	int to;
	int length;
	Edge(int t,int l): to(t),length(l){}
};

struct Point{
	int number;
	int distance;
	Point(int n,int d): number(n), distance(d){}
	bool operator< (const Point& p) const{
		return distance > p.distance;
	}
};

vector<Edge> graph[MAXN];
int dis[MAXN];

void Dijkstra(int s){
	priority_queue<Point> q;
	dis[s] = 0;
	q.push(Point(s,dis[s]));
	while(!q.empty()){
		int u = q.top().number;
		q.pop();
		for(int i = 0;i < graph[u].size();i++){
			int v = graph[u][i].to;
			int d = graph[u][i].length;
			if(dis[v] > dis[u] + d){
				dis[v] = dis[u] + d;
				q.push(Point(v,dis[v]));
			}
		}
	}
}

int main(){
	int n,m;
	while(cin>>n>>m){
		memset(graph,0,sizeof(graph));
		fill(dis,dis+n,INF);
		while(m--){
			int from,to,length;
			cin>>to>>length;
			graph[from].push_back(Edge(to,length));
			graph[to].push_back(Edge(from,length));
			
		}
		int s,t;
		cin>>s>>t;
		Dijkstra(s);
		if(dis[t] == INF) dis[t] = -1;
		cout<<dis[t]<<endl;
	}

	return 0; 
}

4)拓扑排序

1.确定比赛名次

题目描述:

有 N 个比赛队(1 <= N <= 500),依次以编号 1, 2, 3,…, N 进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即 P1 赢 P2,用 P1, P2 表示,排名时 P1 在 P2 之前。现在请你编写程序确定排名。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 501;

vector<int> graph[MAXN];
int inDegree[MAXN];

vector<int> TopologicalSort(int n){
	vector<int> topology;
	priority_queue<int, vector<int>, greater<int> > node;
	for(int i = 1;i <= n;i++){
		if(inDegree[i] == 0){
			node.push(i);
		}
	}
	while(!node.empty()){
		int u = node.top();
		node.pop();
		topology.push_back(u);
		for(int i = 0;i < graph[u].size();i++){
			int v = graph[u][i];
			inDegree[v]--;
			if(inDegree[v] == 0) node.push(v);
		}
	}
	while(!node.empty()){
		int u = node.top();
		node.pop();
		topology.push_back(u);
		for(int i = 0;i < graph[u].size();i++){
			int v = graph[u][i];
			inDegree[v]--;
			if(inDegree[v] == 0) node.push(v);
		}
	}
	return topology;
}

int main(){
	int n,m;
	while(cin>>n>>m){
		memset(graph,0,sizeof(graph));
		memset(inDegree,0,sizeof(inDegree));
		while(m--){
			int from,to;
			cin>>from>>to;
			graph[from].push_back(to);
			inDegree[to]++;
		}
		vector<int> answer = TopologicalSort(n);
		for(int i =0;i < answer.size();i++){
			if(i == 0) cout<<answer[i]<<" ";
			else cout<<answer[i]<<" ";
		}
		cout<<endl;
	}

	return 0; 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@小红花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值