【考研机试刷题】7 数据结构二

7 数据结构二

1 二叉树

本章包括:

  1. 二叉树的建树、遍历
  2. 二叉排序树的建树、遍历
  3. 判断2棵树是否是相同的二叉排序树

例题10.1 二叉树遍历(清华大学复试上机)

题目

题目地址

本题要求递归建立二叉树,而不是使用队列的层次建树方法,“递归建树”后再输出中序遍历序列

例题10.2 二叉树遍历(华中科技大学复试上机)

题目

题目地址

本题较复杂,先从前序和中序序列得到原二叉树,再输出原二叉树后序序列

2 二叉排序/搜索树

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

题目

题目地址

此题值得一练,包含了二叉排序树的建树、前中后序遍历

习题10.1 二叉搜索树(浙江大学复试上机)

题目

题目地址

本题判断2个序列是否为同一个二叉搜索树序列,if(它们的中序和先序都一样),则相同,因为可以唯一确定一颗二叉树

题解
#include <cstdio>
#include <iostream>
#include <string>

using namespace std;

struct TreeNode{
    char data;
    TreeNode* leftchild;
    TreeNode* rightchild;
    //这里使用了构造函数,即创建时就进行初始赋值,注意写法
    TreeNode(char x):data(x),leftchild(NULL),rightchild(NULL){}
};

//这里类型为节点*,所以形参不需要用&引用,但如果用void,则需要写成node* &root
//另外命名可以用Insert而不用Build,否则可能引起歧义
TreeNode* InsertBST(TreeNode* root,char x){    
    if(root == NULL){
        //注意cpp的new的用法,且使用构造函数完成了赋值
        root = new TreeNode(x);
    }
    //插入新结点到排序树时,默认已经递归到最深处无孩子的"root",所以要赋值给child
    //且元素值==root->data时,不插入
    else if(x < root->data){
        root->leftchild = InsertBST(root->leftchild, x);
    }
    else if(x > root->data){
        root->rightchild = InsertBST(root->rightchild, x);
    }
    return root;
}

//先序序列的字符串
string Preorder(TreeNode* root){
    if(root == NULL){
        return "";  //string类型要返回空串
    }
    //返回当前节点作为根节点时的先序序列,则可以递归地得到整个先序序列的字符串
    return root->data + Preorder(root->leftchild) + Preorder(root->rightchild);
}

//中序序列的字符串
string Inorder(TreeNode* root){
    if(root == NULL){
        return "";
    }
    return Inorder(root->leftchild) + root->data + Inorder(root->rightchild);
}


int main(){
    int n;
    string str;
    while(scanf("%d",&n)!=EOF){
        if(n == 0){
            break;
            }

        //tree1是树一的序列,root1是树一的根
        string tree1;
        cin>>tree1; //cin遇分隔符停止,并抛弃结尾分隔符
        TreeNode* root1 = NULL; //要初始化成空指针
        for(int i = 0;i<tree1.size();i++){  //将序列插入树一
            root1 = InsertBST(root1, tree1[i]);
        }
        //保存好先序中序序列,用于一会比较
        string preorder1 = Preorder(root1);
        string inorder1 = Inorder(root1);

        for(int i = 0;i<n;i++){
            string tree2;
            cin>>tree2;
            TreeNode* root2 = NULL; //要初始化成空指针
            for(int j = 0;j<tree2.size();j++){
                root2 = InsertBST(root2, tree2[j]);
            }

            string preorder2 = Preorder(root2);
            string inorder2 = Inorder(root2);

            if(preorder1 == preorder2 && inorder1 == inorder2){
                printf("YES\n");
            }
            else{
                printf("NO\n");
            }
        }
        
    }
}
笔记
  1. 注释较完整
  2. 二叉树节点的数据结构、struct内的构造函数
  3. 二叉排序树的建树、遍历
  4. main函数中对树的初始化,要初始化为空指针,node* root = NULL;

3 优先队列

  1. 优先队列的基本使用:定义 priority_queue<int myPriorityQueue; 增删 push()和pop();访问 myPriorityQueue.top()优先级最高的元素
  2. 按“优先级”排序,默认是大根堆,若想变小根堆 或其他排序方法:可取巧在push前都加个负号,top后再乘-1变回原数;也可以运算符重载,bool operator< (Complex left, Complex right){}

例题10.5 复数集合(北邮复试上机)

题目

题目地址

主要考察了优先队列、运算符重载来比较结构体,

题解
#include <queue>
#include <cstdio>
#include <iostream>
#include <string>
#include <cmath>    //求次幂,是pow,不是power

using namespace std;

struct Complex{
    int real;
    int unreal;
    int mo;
    Complex(int a, int b):real(a),unreal(b),mo(pow(a,2)+pow(b,2)){}
};

bool operator < (Complex left, Complex right){
    //return left.real*left.real + left.unreal*left.unreal < right.real*right.real + right.unreal*right.unreal;
    //这里运算符重载是因为结构体,另外因为是用大根堆,所以仍是<时触发交换,>时是小根堆
    return left.mo < right.mo;
}

int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        priority_queue<Complex> myPriorityQueue;//注意定义的位置
        for(int i = 0;i < n;i++){
            //这里调试好几次才找到错误,用getline好像不会跳过开头的分隔符,故改为直接用cin
            string str;
            cin>>str;

            if(str == "Pop"){
                //操作为pop时
                if(myPriorityQueue.empty()){
                    printf("empty\n");
                }
                else{
                    Complex ccur = myPriorityQueue.top();
                    printf("%d+i%d\n",ccur.real,ccur.unreal);
                    myPriorityQueue.pop();
                    printf("SIZE = %d\n",myPriorityQueue.size());
                }
            }
            else{
                //操作为insert时,还要继续输入l+i2
                int a1,b1;
                //这里的输入方法,按部就班用scanf就好,会跳过前面空格
                scanf("%d+i%d",&a1,&b1);
                Complex ccur(a1,b1);    //这里使用了构造函数,所以下面2行不用了
                //ccur.real = a1;   
                //ccur.unreal = b1;
                myPriorityQueue.push(ccur);
                printf("SIZE = %d\n",myPriorityQueue.size());
            }
        }
    }
}

笔记
  1. 注意构造函数的写法,与cmath中pow函数不是power
  2. 运算符重载:注意是大根堆还是小根堆,默认大根堆,即“<为真时”触发交换,,所以若想在优先队列中使用小根堆,先输出优先级小的,需要运算符重载return >为真时触发交换
  3. 用getline输入str时出错,改用cin后好使,估计是因为cin会跳过开头的分隔符
  4. 输入insert 1+i2时,空格的“后半部分”使用scanf输入,因为会跳过前面空格,注意格式一致

例题10.6 哈夫曼树(北邮复试上机)

题目

题目地址

有上一题的基础,这道题很简单,只需要把所有元素值的负数存入优先队列,然后每次top出2个最大的,也就是原叶子结点中2个权值最小的。

top完别忘pop,再把新节点push进优先队列,用wpl累加,最后输入wpl时别忘再乘回来-1

题解
#include <iostream>
#include <cstdio>
#include <queue>

using namespace std;


int main() {
    int n;
    while (scanf("%d", &n) != EOF) {
        priority_queue<int> myPriorityQueue;
        int wpl = 0;
        for (int i = 0; i < n; i++) {
            int num;
            cin >> num;
            //乘-1再入优先队列,即可巧妙运用默认的大根堆实现小根堆
            myPriorityQueue.push(num * (-1));
        }

        //wpl不断累加,退出条件是优先队列中只有一个根节点
        while (myPriorityQueue.size() > 1) {
            int small1 = myPriorityQueue.top();
            myPriorityQueue.pop();
            int small2 = myPriorityQueue.top();
            myPriorityQueue.pop();
            int newWeight = small1 + small2;
            myPriorityQueue.push(newWeight);//别忘新节点入队

            wpl = wpl + small1 + small2;
        }
        printf("%d\n",wpl*(-1));
    }
}
笔记
  1. 有上一题的基础,稍作改动即可
  2. wpl的巧妙计算方法:wpl=左子树的wpl+左根权+右子树的wpl+右根权,居然被我歪打正着写对了

习题10.2 查找第k小的数(北邮复试上机)

题目

题目地址

仍采用优先队列,元素乘-1再入队,取巧地在优先队列默认大根堆的情况下实现了小根堆,最后别忘乘回来-1即可。

注意:第k小,但相同的元素算同1个,也就是只有所有相同元素都从优先队列pop出去后,才i++。

#include <queue>
#include <cstdio>
#include <iostream>

using namespace std;

int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        priority_queue<int> myPriorityQueue;
        for(int i = 0;i<n;i++){
            int num;
            cin>>num;
            myPriorityQueue.push(num*(-1));
        }

        int k;
        cin>>k;
        for(int i = 0;i<k-1;){//把第k小之前的都出队
            //但是要实现相同大小算一样大,所以要前后比较,分情况讨论
            int curnum1 = myPriorityQueue.top();
            myPriorityQueue.pop();
            int curnum2 = myPriorityQueue.top();
            if(curnum1 == curnum2){
                //如果当前top出的元素与下一个队首元素=,则i不增加
                continue;
            }
            else{
                //只有当当前top出的元素已经是与它相同的最后一个,再i++
                i++;
            }
        }
        int answer =  myPriorityQueue.top()*(-1);
        printf("%d\n",answer);
    }
}
笔记

在本节例题的基础上,本题不算难,注意一些细节。

4 散列表(更多map的使用)

例题10.7 查找学生信息(清华大学复试上机)

题目

题目地址

本题用到了map,关键字为int学号,映射值为string其他信息。
注意map的操作:定义、添加、查找、访问。

题解
#include <map>
#include <cstdio>
#include <string>
#include <iostream>

using namespace std;

int main(){
    int n,m;
    map<int,string> mymap;//定义要使用的map,学号为关键字,其他信息为映射值
    while(scanf("%d",&n)!=EOF){
        for(int i = 0;i<n;i++){
            //每行先读入学号,遇空格停止,cin忽略前面的空格
            int stunum;
            //cin不对后面的分隔符做处理,因此我猜后面用getline时会自动忽略前面的分隔符
            cin>>stunum;    
            //scanf("%d",&stunum);
            string str;
            getline(cin,str);
            mymap[stunum] = str;    //用“下标”的方式给map添加新元素
        }

        scanf("%d",&m);
        for(int j = 0;j < m;j++){
            int searchnum;
            scanf("%d",&searchnum);
            if(mymap.find(searchnum)!=mymap.end()){//注意在map中查找的写法
                if(searchnum<10){
                    //看示例后原本以为学号<10时要前面加0,但是测试用例中不需要加0,坑人
                    printf("%d%s\n",searchnum,mymap[searchnum].c_str());
                }
                else{
                    printf("%d%s\n",searchnum,mymap[searchnum].c_str());
                }
                
            }
            else{
                printf("No Answer!\n");
            }
        }
    }
}
笔记
  1. 本题也可以创建一个struct存储学号以外的信息,然后map<int,struct>即可
  2. 想实现把一行中空格隔开的部分分别输入到不同变量,可以cin和getline连续使用,,也可以直接getline然后再
  3. 用scanf输出string类型时,加上.c_str()。
  4. 输出格式可能给错,可以留意一下。
  5. map的定义、状态、添加、访问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值