数据结构基础知识——非线性数据结构(二叉树、二叉排序树、优先队列、散列表)

目录:

  1. 基础知识

    1. 二叉树
    2. 二叉排序树
    3. 优先队列
    4. 哈夫曼树
    5. 散列表
  2. 应用实例
    1. 哈夫曼树【北京邮电大学】
    2. 复数集合【北京邮电大学】
    3. 二叉搜索树【浙江大学】
    4. 二叉树遍历【清华大学】
    5. 二叉树遍历【华中科技大学】
    6. 二叉排序树Ⅰ【华中科技大学】
    7. 二叉排序树Ⅱ【华中科技大学】
    8. 查找学生信息【清华大学】
    9. 魔咒词典【浙江大学】
    10. 子串计算【北京大学】
    11. 统计同成绩学生人数【浙江大学】
    12. 开门人和关门人【浙江大学】

一、基础知识

1、二叉树(Binary Tree):

(1)定义:二叉树要么为空,要么由根结点(Root)、左子树(Left Subtree)和右子树(Right Subtree)构成,而左右两个子树又分别是一棵二叉树。

(2)结构体定义:

  • struct TreeNode{
  • ElementType data;
  • TreeNode *lchild, *rchild;
  • };

(3)根据遍历每个结点的左子树L、结点本身N、右子树R的顺序不同,可将对二叉树的遍历方法分为前序遍历(NLR),中序遍历(LNR),后序遍历(LRN),其中的序是指根结点在何时被访问。

  • 前序遍历(PreOrder):

    • void PreOrder(TreeNode *T){
    • if(T != NULL){
    • Visit(T->data);
    • PreOrder(T->leftchild);
    • PreOrder(T->rchild);
    • }
    • }
  • 中序遍历(InOrder):
    • void InOrder(TreeNode *T){
    • if(T != NULL){
    • PreOrder(T->leftchild);
    • Visit(T->data);
    • PreOrder(T->rchild);
    • }
    • }
  • 后序遍历(PostOrder):
    • void PostOrder(TreeNode *T){
    • if(T != NULL){
    • PreOrder(T->leftchild);
    • PreOrder(T->rchild);
    • Visit(T->data);
    • }
    • }
  • 层次遍历(LevelOrder):需要借助一个队列实现。先将二叉树的根结点入队,在队伍非空的情况下访问队首结点,若它有左子树,则将左子树根结点入队;若它有右子树,则将右子树根结点入队。如此反复,直到队列为空为止。
    • void LevelOrder(TreeNode *T){
    • queue<TreeNode *> q;
    • if(T){
    • q.push(T);
    • }
    • while(!q.empty()){
    • TreeNode *current = q.front();
    • q.pop();
    • Visit(current->data);
    • if(current->lchild){
    • q.push(current->lchild);
    • }
    • if(current->rchild){
    • q.push(current->rchild);
    • }
    • }
    • }

(4)根据先序遍历、中序遍历确定一棵二叉树:

  • 在先序遍历中,第一个结点必定是二叉树的根结点;
  • 在中序遍历中,该根结点必定可将中序遍历的序列分为两个子序列,前一个子序列是根结点左子树的中序遍历序列,后一个子序列是根结点右子树的中序遍历序列;
  • 递归下去,则可以唯一确定该二叉树。

2、二叉排序树(Binary Search Tree):

(1)定义:对于一棵非空二叉排序树,

  • 若左子树非空,则左子树上所有结点关键字的值均小于根结点关键字的值;
  • 若右子树非空,则右子树上所有结点关键字的值均大于根结点关键字的值;
  • 左右子树本身也是一棵二叉排序树。

(2)特点:

  • 各个数字的插入顺序不同,则得到的二叉排序树的形态可能不同。
  • 对二叉排序树进行中序遍历,会得到一个升序序列。
  • 通过建立一棵二叉排序树,就能对原本无序的序列进行排序,并实现序列的动态维护。

3、优先队列(Priority Queue):

(1)定义:能够将元素按照事先规定的优先级次序进行动态组织,访问元素时,只能访问当前队列中优先级最高的元素,即最高级先出(First-In Greatest-Out)。

(2)STL-priority_queue:

  • #include <queue>,先出队列的元素是队列中优先级最高的元素。用priority_queue<int> pq方式声明一个队列,取队首元素的方法由queue的front()变为了top()。
  • 常用方法:
    • priority_queue的状态:

      • pq.size():返回当前优先队列的元素个数。
      • pq.empty():返回当前优先队列是否为空。
    • priority_queue元素的添加或删除:
      • pq.push():元素的入队。
      • pq.pop():元素的出队。
    • priority_queue元素的访问:
      • pq.top():访问当前优先队列中优先级最高的元素。

4、哈夫曼树/最优树(Huffman Tree):

(1)定义:给定n个带有权值的结点,以它们为叶子结点构造一棵带权路径长度和最小的二叉树。

  • 路径:一棵树中从任意一个结点到达另一个结点的通路。
  • 路径长度:路径上所需经过的边的个数。
  • 带权路径长度:从根结点到达该结点的路径长度再乘以该结点的权值称为该结点的带权路径长度。
  • 树的带权路径长度:所有叶子结点的带权路径长度之和。

(2)特点:

  • n个带有权值的结点构成的哈夫曼树可能不唯一。

5、散列表(Hash Table)/ Map(映射/关联数组):

(1)定义:一种根据关键字(key)直接访问值(Value)的数据结构。

(2)特点:

  • 由于散列表摒弃了关键码有序,因此在理想情况下可在期望的常数时间内实现所有接口操作。就平均时间复杂度的意义而言,这些操作的复杂度都是O(1).

(3)STL-map:

  • #include <map>,map是从键(key)到值(value)的映射。因为重载了[]运算符,map像是数组的高级版,如可以用map<string, int> month_name来表示月份名字到月份编号的映射,然后用month_name["July"] = 7的方式来赋值。
  • map的底层由红黑树实现,内部仍然是有序的,其查找效率仍然为O(logn)。
  • 无序映射unordered_map的底层是用散列表实现的,其期望的查找效率为O(1)。
  • 常用方法:
    • map的状态:

      • map.empty():返回当前映射是否为空。
      • map.size():返回当前映射元素个数。
    • map元素的添加或删除:
      • insert():实现元素的添加。
      • erase():实现元素的删除。
    • map元素的访问:
      • 由于map内部重载了[]运算符,因此可以通过[key]的方式访问。
      • 通过at()进行访问。
      • 通过迭代器进行访问。
    • map元素操作:
      • find():查找特定的元素,找到则返回元素的迭代器,未找到则返回迭代器end()。
      • clear():将映射清空。
    • map迭代器操作:
      • begin():返回映射中首元素迭代器。
      • end():返回映射中尾元素之后一个位置的迭代器。

示例代码:

#include <iostream>
#include <map>
#include <string>using namespace std;map<string, int> myMap;int main(){//1、插入四个元素myMap["Dodo"] = 408;myMap["Tom"] = 308;myMap.insert(pair<string, int>("Jerry", 208));myMap.insert(pair<string, int>("Lisa", 108));//2、在map中键是唯一的,重复插入一个Dodo键,系统会忽略后面的对已存在的键的插入操作myMap.insert(pair<string, int>("Dodo", 333));//3、修改Lisa的值为222,然后遍历mapmyMap["Lisa"] = 222;for(map<string, int>::iterator iter = myMap.begin(); iter != myMap.end(); iter++){cout << (*iter).first << ": " << iter->second << endl;}//4、Jerry键的值,Lisa的值cout << myMap.at("Jerry") << ", " << myMap["Lisa"] << endl;//5、map的sizecout << "map's size is : " << myMap.size() << endl;//6、删除JerrymyMap.erase("Jerry"); cout << "After delete Jerry, Size is:" << myMap.size() << endl;myMap.clear();if(myMap.empty()){cout << "it is empty" << endl;}//7、释放内存map<string, int> tmp_map;myMap.swap(tmp_map);return 0;
}

二、应用实例

1、题目描述:哈夫曼树,第一行输入一个数n,表示叶结点的个数。需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,题目需要输出所有结点的权值与路径长度的乘积之和。【北京邮电大学】

  • 输入格式:输入有多组数据。每组第一行输入一个数n,接着输入n个叶节点(叶节点权值不超过100,2<=n<=1000)。
  • 输出格式:输出所有结点的权值与路径长度的乘积之和
  • 样例输入:
    • 5
    • 1 2 2 5 9
  • 样例输出:
    • 37

示例代码1:

#include <iostream>
#include <functional>
#include <queue>using namespace std;priority_queue<int, vector<int>, greater<int> > pq; //优先队列按照小顶堆的方式输出int main(){int n;while(cin >> n){for(int i = 0; i < n; i++){int number;cin >> number;pq.push(number);}int answer = 0;while(pq.size() > 1){int min1 = pq.top();pq.pop();int min2 = pq.top();pq.pop();answer += min1 + min2;pq.push(min1 + min2);}cout << answer << endl;if(!pq.empty()){pq.pop();}}  return 0;
}

示例代码2:

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;vector<int> vec;bool compDesc(const int &a, const int &b){return b < a;
}int main(){int n;while(cin >> n){for(int i = 0; i < n; i++){int number;cin >> number;vec.push_back(number);}int result = 0;while(vec.size() >= 2){sort(vec.begin(), vec.end(), compDesc);//降序排序int min1 = vec.back();vec.pop_back();int min2 = vec.back();vec.pop_back();vec.push_back(min1 + min2);result += min1 + min2;}cout << result << endl;vec.clear();}return 0;
}

2、题目描述:一个复数(x+iy)集合,两种操作作用在该集合上:     1、Pop 表示读出集合中复数模值最大的那个复数,如集合为空 输出  empty  ,不为空就输出最大的那个复数并且从集合中删除那个复数,再输出集合的大小SIZE;     2 Insert a+ib  指令(a,b表示实部和虚部),将a+ib加入到集合中 ,输出集合的大小SIZE;     最开始要读入一个int n,表示接下来的n行每一行都是一条命令。【北京邮电大学】

  • 输入格式:输入有多组数据。每组输入一个n(1<=n<=1000),然后再输入n条指令。
  • 输出格式:根据指令输出结果。模相等的输出b较小的复数。a和b都是非负数。
  • 样例输入:
    • 3
    • Pop
    • Insert 1+i2
    • Pop
  • 样例输出:
    • empty
    • SIZE = 1
    • 1+i2
    • SIZE = 0

示例代码:

#include <iostream>
#include <queue>
#include <string>
#include <algorithm>using namespace std;struct Complex{int x;int iy;Complex(int x, int iy):x(x),iy(iy){}
};priority_queue<Complex> pq;bool operator<(Complex a, Complex b){ //返回true说明a的优先级低于bdouble aComp = pow(a.iy, 2) + pow(a.x, 2), bComp = pow(b.iy, 2) + pow(b.x, 2);if(aComp > bComp){return false;}else if(aComp < bComp){return true;}else{return a.iy > b.iy;}
}int GetNumber(string s, int &index){int number = 0;while(isdigit(s[index])){number = number * 10 + s[index] - '0';index++;}return number;
}int main(){int n;while(cin >> n){getchar();for(int i = 0; i < n; i++){string s;getline(cin, s);if(s == "Pop"){if(pq.empty()){cout << "empty" << endl;}else{cout << pq.top().x << "+i" << pq.top().iy << endl;pq.pop();cout << "SIZE = " << pq.size() << endl;}}else if(s.find("Insert") != -1){int index = 0;while(!isdigit(s[index])){index++;}int x = GetNumber(s, index);while(!isdigit(s[index])){index++;}int iy = GetNumber(s, index);pq.push(Complex(x, iy));cout << "SIZE = " << pq.size() << endl;}}if(!pq.empty()){pq.pop();}}return 0;
}

3、判断两序列是否为同一二叉搜索树序列【浙江大学】

  • 输入格式:开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束。接下去一行是一个序列,序列长度小于10,包含(0~9)的数字,没有重复数字,根据这个序列可以构造出一颗二叉搜索树。接下去的n行有n个序列,每个序列格式跟第一个序列一样,请判断这两个序列是否能组成同一颗二叉搜索树。
  • 输出格式:如果序列相同则输出YES,否则输出NO
  • 样例输入:
    • 2
    • 567432
    • 543267
    • 576342
    • 0
  • 样例输出:
    • YES
    • NO

示例代码:

#include <iostream>
#include <string>
#include <vector>using namespace std;string originStr;
string tmpStr;struct TreeNode{int data;struct TreeNode *left, *right;TreeNode(int x):data(x),left(NULL), right(NULL){}
};TreeNode* InsertNode(TreeNode *T, int x){if(T == NULL){T = new TreeNode(x);}else if(x < T->data){T->left = InsertNode(T->left, x);}else if(x > T->data){T->right = InsertNode(T->right, x);}return T;
}TreeNode* createTree(string s, TreeNode *T){for(int i = 0; i < s.size(); i++){T = InsertNode(T, s[i]);}return T;
}void InOrder(TreeNode *T, vector<int> &v){if(T != NULL){InOrder(T->left, v);v.push_back(T->data);InOrder(T->right, v);}
}void PreOrder(TreeNode *T, vector<int> &v){if(T != NULL){v.push_back(T->data);PreOrder(T->left, v);PreOrder(T->right, v);}
}//判断二者先序遍历和中序遍历序列是否一致
bool IsCorrespond(vector<int> a, vector<int> b){if(a.size() != b.size()){return false;}vector<int>::iterator iterA, iterB;for(iterA = a.begin(), iterB = b.begin(); iterA != a.end() && iterB != b.end() && (*iterA) == (*iterB); iterA++, iterB++){}if(iterA == a.end()){return true;}return false;
}int main(){int n;while(cin >> n && n){cin >> originStr;TreeNode *originalTree = NULL;originalTree = createTree(originStr, originalTree);vector<int> originInOrderVector, originPreOrderVector;InOrder(originalTree, originInOrderVector);PreOrder(originalTree, originPreOrderVector);vector<int> tmpInOrderVector, tmpPreOrderVector;for(int i = 0; i < n; i++){cin >> tmpStr;TreeNode *tmpTree = NULL;tmpTree = createTree(tmpStr, tmpTree);InOrder(tmpTree, tmpInOrderVector);PreOrder(tmpTree, tmpPreOrderVector);if(IsCorrespond(tmpInOrderVector, originInOrderVector) && IsCorrespond(tmpPreOrderVector, originPreOrderVector)){cout << "YES" << endl;}else{cout << "NO" << endl;}tmpInOrderVector.clear();tmpPreOrderVector.clear();}originInOrderVector.clear();originPreOrderVector.clear();}return 0;
}

4、题目描述:编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。【清华大学】

  • 输入格式:输入包括1行字符串,长度不超过100。
  • 输出格式:可能有多组测试数据,对于每组数据,输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。每个输出结果占一行。
  • 样例输入:
    • abc##de#g##f###
  • 样例输出:
    • c b e g d f a

示例代码:

#include <iostream>
#include <string>using namespace std;struct TreeNode{char data;struct TreeNode *left, *right;TreeNode(char data):data(data), left(NULL), right(NULL){}
};TreeNode* InsertNode(string str, int &pos){char c = str[pos++];if(c == '#'){return NULL;}TreeNode *T = new TreeNode(c);T->left = InsertNode(str, pos);T->right = InsertNode(str, pos);return T;
}void InOrder(TreeNode *T){if(T != NULL){InOrder(T->left);if(T->data != '#'){cout << T->data << " ";}InOrder(T->right);}
}int main(){string s;while(cin >> s){int pos = 0;TreeNode *T = InsertNode(s, pos);InOrder(T);cout << endl;}return 0;
}

5、题目描述:二叉树的前序、中序、后序遍历的定义: 前序遍历:对任一子树,先访问跟,然后遍历其左子树,最后遍历其右子树; 中序遍历:对任一子树,先遍历其左子树,然后访问根,最后遍历其右子树; 后序遍历:对任一子树,先遍历其左子树,然后遍历其右子树,最后访问根。 给定一棵二叉树的前序遍历和中序遍历,求其后序遍历(提示:给定前序遍历与中序遍历能够唯一确定后序遍历)。【华中科技大学】

  • 输入格式:两个字符串,其长度n均小于等于26。第一行为前序遍历,第二行为中序遍历。二叉树中的结点名称以大写字母表示:A,B,C....最多26个结点。
  • 输出格式:输入样例可能有多组,对于每组测试样例,输出一行,为后序遍历的字符串。
  • 样例输入:
    • ABC
    • BAC
    • FDXEAG
    • XDEFAG
  • 样例输出:
    • BCA
    • XEDGAF

示例代码:

#include <iostream>
#include <string>using namespace std;struct TreeNode{char data;struct TreeNode *lchild, *rchild;TreeNode(char c):data(c), lchild(NULL), rchild(NULL){}
};TreeNode* CreateTree(string preStr, string inStr){if(preStr.size() == 0 || inStr.size() == 0){return NULL;}char c = preStr[0];TreeNode *T = new TreeNode(c);int pos = inStr.find(c);T->lchild = CreateTree(preStr.substr(1, pos), inStr.substr(0, pos));T->rchild = CreateTree(preStr.substr(pos + 1), inStr.substr(pos + 1));return T;
}void PostOrder(TreeNode *T){if(T != NULL){PostOrder(T->lchild);PostOrder(T->rchild);cout << T->data;}
}int main(){string preStr, inStr;while(cin >> preStr && cin >> inStr){TreeNode *T = CreateTree(preStr, inStr);PostOrder(T);cout << endl;}return 0;
}

若已知中序遍历序列和后序遍历序列,求前序遍历序列示例代码:

#include <iostream>
#include <string>using namespace std;struct TreeNode{char data;struct TreeNode *lchild, *rchild;TreeNode(char c):data(c), lchild(NULL), rchild(NULL){}
};TreeNode* CreateTree(string inStr, string postStr){if(inStr.size() == 0 || postStr.size() == 0){return NULL;}char c = postStr[postStr.size() - 1];TreeNode *T = new TreeNode(c);int pos = inStr.find(c);T->lchild = CreateTree(inStr.substr(0, pos), postStr.substr(0, pos));T->rchild = CreateTree(inStr.substr(pos + 1), postStr.substr(pos, postStr.size() - pos - 1));return T;
}void PreOrder(TreeNode *T){if(T != NULL){cout << T->data;PreOrder(T->lchild);PreOrder(T->rchild);}
}int main(){string inStr, postStr;while(cin >> inStr >> postStr){TreeNode *T = CreateTree(inStr, postStr);PreOrder(T);cout << endl;}return 0;
}/* 测试样例:
输入:
BAC
BCA
XDEFAG
XEDGAF
DBHIEAFCGKJ
DIHEBFKJGCA输出:
ABC
FDXEAG
ABDEHICFGJK*/

6、题目描述:输入一系列整数,建立二叉排序树,并进行前序,中序,后序遍历。【华中科技大学】

  • 输入格式:输入第一行包括一个整数n(1<=n<=100)。接下来的一行包括n个整数。
  • 输出格式:可能有多组测试数据,对于每组数据,将题目所给数据建立一个二叉排序树,并对二叉排序树进行前序、中序和后序遍历。每种遍历结果输出一行。每行最后一个数据之后有一个空格。输入中可能有重复元素,但是输出的二叉树遍历序列中重复元素不用输出。
  • 样例输入:
    • 5
    • 1 6 5 9 8
  • 样例输出:
    • 1 6 5 9 8
    • 1 5 6 8 9
    • 5 8 9 6 1

示例代码:

#include <iostream>
#include <string>using namespace std;struct TreeNode{int data;struct TreeNode *lchild, *rchild;TreeNode(int i):data(i), lchild(NULL), rchild(NULL){}
};TreeNode* InsertNode(TreeNode *T, int data){if(T == NULL){T = new TreeNode(data);}else if(data > T->data){T->rchild = InsertNode(T->rchild, data);}else if(data < T->data){T->lchild = InsertNode(T->lchild, data);}return T;
}int GetNumber(string s, int &index){int number = 0;while(isdigit(s[index])){number = number * 10 + s[index] - '0';index++;}return number;
}TreeNode* CreateTree(string s){int i = 0;TreeNode *T = NULL;while(i < s.size()){if(isdigit(s[i])){T = InsertNode(T, GetNumber(s, i));}i++;}return T;
}void PreOrder(TreeNode *T){if(T != NULL){cout << T->data << " ";PreOrder(T->lchild);PreOrder(T->rchild);}
}void InOrder(TreeNode *T){if(T != NULL){InOrder(T->lchild);cout << T->data << " ";InOrder(T->rchild);}
}void PostOrder(TreeNode *T){if(T != NULL){PostOrder(T->lchild);PostOrder(T->rchild);cout << T->data << " ";}
}int main(){int n;string str;while(cin >> n){getchar();getline(cin, str);TreeNode *T = CreateTree(str);PreOrder(T);cout << endl;InOrder(T);cout << endl;PostOrder(T);cout << endl;}return 0;
}

7、题目描述:二叉排序树,也称为二叉查找树。可以是一颗空树,也可以是一颗具有如下特性的非空二叉树: 1. 若左子树非空,则左子树上所有节点关键字值均不大于根节点的关键字值; 2. 若右子树非空,则右子树上所有节点关键字值均不小于根节点的关键字值; 3. 左、右子树本身也是一颗二叉排序树。 现在给你N个关键字值各不相同的节点,要求你按顺序插入一个初始为空树的二叉排序树中,每次插入后成功后,求相应的父亲节点的关键字值,如果没有父亲节点,则输出-1。【华中科技大学】

  • 输入格式:输入包含多组测试数据,每组测试数据两行。第一行,一个数字N(N<=100),表示待插入的节点数。第二行,N个互不相同的正整数,表示要顺序插入节点的关键字值,这些值不超过10^8。
  • 输出格式:输出共N行,每次插入节点后,该节点对应的父亲节点的关键字值。
  • 样例输入:
    • 5
    • 2 5 1 3 4
  • 样例输出:
    • -1
    • 2
    • 2
    • 5
    • 3

示例代码:

#include <iostream>
#include <string>using namespace std;struct TreeNode{int data;struct TreeNode *lchild, *rchild;TreeNode(int i):data(i), lchild(NULL), rchild(NULL){}
};TreeNode* InsertNode(TreeNode *T, int data, TreeNode *parent){if(T == NULL){T = new TreeNode(data);if(parent){cout << parent->data << endl;}else{cout << -1 << endl;}}else if(data > T->data){T->rchild = InsertNode(T->rchild, data, T);}else if(data < T->data){T->lchild = InsertNode(T->lchild, data, T);}return T;
}int GetNumber(string s, int &index){int number = 0;while(isdigit(s[index])){number = number * 10 + s[index] - '0';index++;}return number;
}TreeNode* CreateTree(string s){int i = 0;TreeNode *T = NULL;while(i < s.size()){if(isdigit(s[i])){T = InsertNode(T, GetNumber(s, i), NULL);}i++;}return T;
}int main(){int n;string str;while(cin >> n){getchar();getline(cin, str);TreeNode *T = CreateTree(str);}return 0;
}

8、题目描述:输入N个学生的信息,然后进行查询。【清华大学】

  • 输入格式:输入的第一行为N,即学生的个数(N<=1000)
    接下来的N行包括N个学生的信息,信息格式如下:
    01 李江 男 21
    02 刘唐 男 23
    03 张军 男 19
    04 王娜 女 19
    然后输入一个M(M<=10000),接下来会有M行,代表M次查询,每行输入一个学号,格式如下:
    02
    03
    01
    04
  • 输出格式:输出M行,每行包括一个对应于查询的学生的信息。如果没有对应的学生信息,则输出“No Answer!”
  • 样例输入:
    • 4
    • 01 李江 男 21
    • 02 刘唐 男 23
    • 03 张军 男 19
    • 04 王娜 女 19
    • 5
    • 02
    • 03
    • 01
    • 04
    • 03
  • 样例输出:
    • 02 刘唐 男 23
    • 03 张军 男 19
    • 01 李江 男 21
    • 04 王娜 女 19
    • 03 张军 男 19

示例代码:

#include <iostream>
#include <map>
#include <string>using namespace std;struct Student{string name;string sex;int age;Student(){}Student(string n, string s, int a):name(n), sex(s), age(a){}
};map<string, Student> myMap;int main(){int n, searchN;cin >> n;getchar();string code, name, sex;int age;for(int i = 0; i < n; i++){cin >> code;cin >> name;cin >> sex;cin >> age;Student *stu = new Student(name, sex, age);myMap.insert(pair<string, Student>(code, *stu));}cin >> searchN;for(int i = 0; i < searchN; i++){cin >> code;map<string, Student>::iterator it = myMap.find(code);if(it == myMap.end()){cout << "No Answer!" << endl;}else{Student stu = myMap[code];cout << code << " " << stu.name << " " << stu.sex << " " << stu.age << endl;}}myMap.clear();return 0;
}

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

  • 输入格式:首先列出词典中不超过100000条不同的魔咒词条,每条格式为:[魔咒] 对应功能
    其中“魔咒”和“对应功能”分别为长度不超过20和80的字符串,字符串中保证不包含字符“[”和“]”,且“]”和后面的字符串之间有且仅有一个空格。词典最后一行以“@END@”结束,这一行不属于词典中的词条。
    词典之后的一行包含正整数N(<=1000),随后是N个测试用例。每个测试用例占一行,或者给出“[魔咒]”,或者给出“对应功能”。
  • 输出格式:每个测试用例的输出占一行,输出魔咒对应的功能,或者功能对应的魔咒。如果魔咒不在词典中,就输出“what?”
  • 样例输入:
    • [expelliarmus] the disarming charm
    • [rictusempra] send a jet of silver light to hit the enemy
    • [tarantallegra] control the movement of one's legs
    • [serpensortia] shoot a snake out of the end of one's wand
    • [lumos] light the wand
    • [obliviate] the memory charm
    • [expecto patronum] send a Patronus to the dementors
    • [accio] the summoning charm
    • @END@
    • 4
    • [lumos]
    • the summoning charm
    • [arha]
    • take me to the sky
  • 样例输出:
    • light the wand
    • accio
    • what?
    • what?

示例代码:

#include <iostream>
#include <map>
#include <string>using namespace std;map<string, string> magicMap; //key为魔法名,value为解释
map<string, string> infoMap;  //key为解释,value为魔法名int main(){string str;while(getline(cin, str) && str != "@END@"){int index = str.find("]");magicMap.insert(pair<string, string>(str.substr(0, index + 1), str.substr(index + 2)));infoMap.insert(pair<string, string>(str.substr(index + 2), str.substr(1, index - 1)));}int N;cin >> N;getchar();for(int i = 0; i < N; i++){getline(cin, str);map<string, string>::iterator iter1 = magicMap.find(str);map<string, string>::iterator iter2 = infoMap.find(str);if(iter1 != magicMap.end()){cout << magicMap[str] << endl;}else if(iter2 != infoMap.end()){cout << infoMap[str] << endl;}else{cout << "what?" << endl;}}return 0;
}

10、给出一个01字符串(长度不超过100),求其每一个子串出现的次数。【北京大学】

  • 输入格式:输入包含多行,每行一个字符串。
  • 输出格式:对每个字符串,输出它所有出现次数在1次以上的子串和这个子串出现的次数,输出按字典序排序。
  • 样例输入:
    • 10101
  • 样例输出:
    • 0 2
    • 01 2
    • 1 3
    • 10 2
    • 101 2

示例代码:

#include <iostream>
#include <map>
#include <string>using namespace std;map<string, int> myMap;int main(){string str;cin >> str;for(int i = 0; i < str.size(); i++){for(int j = 1; j <= str.size() - i; j++){if(myMap[str.substr(i, j)] == 0){myMap[str.substr(i, j)] = 1;}else{myMap[str.substr(i, j)]++;}}}for(map<string, int>::iterator iter = myMap.begin(); iter != myMap.end(); iter++){if(iter->second >= 2){cout << iter->first << " " << iter->second << endl;}}return 0;
}

附注:

(1)if else也可以直接写为:

for(int j = 1; j <= str.size() - i; j++){
    myMap[str.substr(i, j)]++; //map[key]不存在时返回value的缺省值
}

11、题目描述:读入N名学生的成绩,将获得某一给定分数的学生人数输出。【浙江大学】

  • 输入格式:测试输入包含若干测试用例,每个测试用例的格式为第1行:N;第2行:N名学生的成绩,相邻两数字用一个空格间隔;第3行:给定分数;当读到N=0时输入结束。其中N不超过1000,成绩分数为(包含)0到100之间的一个整数。
  • 输出格式:对每个测试用例,将获得给定分数的学生人数输出。
  • 样例输入:
    • 3
    • 80 60 90
    • 60
    • 2
    • 85 66
    • 0
    • 5
    • 60 75 90 55 75
    • 75
    • 0
  • 样例输出:
    • 1
    • 0
    • 2

示例代码:

#include <iostream>
#include <map>using namespace std;map<int, int> gradeMap;int main(){int number;while(cin >> number && number){int grade, searchGrade;for(int i = 0; i < number; i++){cin >> grade;gradeMap[grade]++;}cin >> searchGrade;cout << gradeMap[searchGrade] << endl;gradeMap.clear();}return 0;
}

12、题目描述:每天第一个到机房的人要把门打开,最后一个离开的人要把门关好。现有一堆杂乱的机房签到、签离记录,请根据记录找出当天开门和关门的人。【浙江大学】

  • 输入格式:每天的记录在第一行给出记录的条目数M (M > 0 ),下面是M行,每行的格式为:证件号码 签到时间 签离时间
    其中时间按“小时:分钟:秒钟”(各占2位)给出,证件号码是长度不超过15的字符串。
  • 输出格式:对每一天的记录输出1行,即当天开门和关门人的证件号码,中间用1空格分隔。注意:在裁判的标准测试输入中,所有记录保证完整,每个人的签到时间在签离时间之前,且没有多人同时签到或者签离的情况。
  • 样例输入:
    • 3
    • CS301111 15:30:28 17:00:10
    • SC3021234 08:00:00 11:25:25
    • CS301133 21:45:00 21:58:40
  • 样例输出:
    • SC3021234 CS301133

示例代码:

#include <iostream>
#include <map>
#include <string>using namespace std;map<string, string> comeMap; //到来Map,key为签到时间,value为证件号码
map<string, string> outMap;  //离开Map,key为签离时间,value为证件号码int main(){int n;cin >> n;for(int i = 0; i < n; i++){string code, comeTime, outTime;cin >> code;cin >> comeTime;cin >> outTime;comeMap[comeTime] = code;outMap[outTime] = code;}cout << comeMap.begin()->second << " " << outMap.rbegin()->second << endl;return 0;
}

参考文献:

[1]刘汝佳. 算法竞赛入门经典(第2版). [M]北京:清华大学出版社,2014.06;

[2]杨泽邦、赵霖. 计算机考研——机试指南(第2版). [M]北京:电子工业出版社,2019.11;

数据结构基础知识——非线性数据结构(二叉树、二叉排序树、优先队列、散列表)相关推荐

  1. 1. 数据结构基础知识

    1. 数据结构基础知识 基本概念 线性结构:结构中的数据元素之间只存在一对一的关系. 树形结构:结构中的数据元素之间存在一对多的关系. 图状结构或网状结构:结构中的数据元素之间存在多对多的关系. 数据 ...

  2. 数据结构基础知识(2)

    内容接自<数据结构基础知识(1)>... 链表的分类 单链表 单链表是一种链式存取的结构,为找第 i 个数据元素,必须先找到第 i-1 个数据元素.图中阴影区域表示数据域,空白区表示指针域 ...

  3. Algorithm:【Algorithm算法进阶之路】之数据结构基础知识

    Algorithm:[Algorithm算法进阶之路]之数据结构基础知识 相关文章 Algorithm:[Algorithm算法进阶之路]之数据结构二十多种算法演示 Algorithm:[Algori ...

  4. 【JavaSE专栏内容导航】JavaSE与数据结构基础知识系列

    ⭐️前面的话⭐️ 大家好!这是Java基础知识与数据结构博文的导航帖,收藏我!学习Java不迷路! 专栏地址:https://blog.csdn.net/m0_59139260/category_11 ...

  5. 数据结构基础知识核心归纳(一)

    数据结构基础知识核心归纳(一) 转载请声明出处:http://blog.csdn.net/andrexpert/article/details/77900395 Android             ...

  6. 【数据结构基础】线性数据结构——栈和队列的总结及封装(C和java)

    前言 数据结构,一门数据处理的艺术,精巧的结构在一个又一个算法下发挥着他们无与伦比的高效和精密之美,在为信息技术打下坚实地基的同时,也令无数开发者和探索者为之着迷. 也因如此,它作为博主大二上学期最重 ...

  7. 【数据结构基础】线性数据结构——线性表概念 及 数组的封装(C和Java)

    前言 数据结构,一门数据处理的艺术,精巧的结构在一个又一个算法下发挥着他们无与伦比的高效和精密之美,在为信息技术打下坚实地基的同时,也令无数开发者和探索者为之着迷. 也因如此,它作为博主大二上学期最重 ...

  8. 算法与数据结构基础四----数据结构基础之动态数据结构基础:链表上

    接着上一次https://www.cnblogs.com/webor2006/p/15195969.html的数据结构继续往下学习,这次会进入一个非常重要的数据结构的学习----链表,这个是未来学习复 ...

  9. 《数据结构与算法》(二十)- 散列表查找

    目录 前言 1. 散列表查找(哈希表)概述 1.1 散列表查找定义 1.2 散列表查找步骤 2. 散列函数的构造方法 2.1 直接定址法 2.2 数字分析法 2.3 平方取中法 2.4 折叠法 2.5 ...

  10. 数据结构 day07 基础知识学习 (二叉树 的 前中后遍历 ,插入节点,删除叶子节点, 二叉树的节点个数 )

    一.今天有点迷. 二.希望大家看的懂代码 ,我已经很努力写注释了. 三.这次的知识很基础 ,(老师关于 二叉树节点删除的哪里 讲的有点差 ,主要是讲之前没有打好框架   (关于父节点的定义   )  ...

最新文章

  1. RPM包制作之Spec文件详解
  2. 获取昨天凌晨毫秒数_Java 获取当前时间距离当天凌晨的秒数
  3. MySQL的配置文件_选项文件_参数文件
  4. 【angularJS】简介
  5. 计算机绘图模型的参数方程,关于曲线绘图与运动控制问题的研究.doc
  6. 一文搞懂IT基础知识,讲通HTTP、TCP、IP、以太网
  7. 学习JavaScript需要什么基础?
  8. c语言中转义字符 0,【填空题】在C语言中,用“\\”开头的字符序列称为转义字符, 转义字符‘\\n’的功能是_____; 转义字符‘\\0’的功能是_____;...
  9. springbatch读取文件_通过例子讲解Spring Batch入门,优秀的批处理框架
  10. sqlserver 建表指定主键_3-自增字段;主键约束
  11. MFC中显示一张位图
  12. 2022年定位系泊系统市场深度分析及发展研究预测报告
  13. 微专题:数据中心选址
  14. 计蒜客--T1212 仙岛求药
  15. HTTP 405Method not allowed
  16. 写自己的故事,帮别人说话
  17. WIN10安装VC6.0无法使用的解决办法
  18. 【数据结构与算法】动态规划-leetcode.1884 鸡蛋掉落两枚鸡蛋
  19. 双臂机器人驱动板(LM324运放电流检测、PCF8591外置ADC)
  20. 【FreeRTOS】06 临界段的保护——关中断和关调度

热门文章

  1. single-spa
  2. Activity任务栈
  3. 京东API接口:item_search - 按关键字搜索商品
  4. 计算机管理里边设置访问权限,电脑访问权限设置_电脑软件访问权限设置
  5. 深度学习之图像分类(二十一)-- MLP-Mixer网络详解
  6. tomcat配置ssl证书
  7. 一个简单的form表单登录界面
  8. STM32定时器周期任务函数编写
  9. 致那些徘徊在测试界的屌丝——也致给我自己这个苦逼屌丝
  10. 用Python制作我的核酸检测日历