机试指南:Ch9:树 Ch10:搜索

文章目录

第7章 非线性数据结构

1.C++的内存模型(内存空间、内存布局、内存分配方式)

1.bss段

未初始化数据段。不保存在硬盘上,只是记录数据所需空间的大小,程序开始执行之前,由内核进行初始化为0

2.data段/数据段/常量区

①初始化的字段,包含明确的初始化值,保存在硬盘上,由.exec读取

②初始化之后的全局变量,静态变量和常量数据,直到程序结束才会被回收

3.text段

存放文本指令的地方,保存在硬盘上,只读的,不可修改,由.exec程序读取。可共享,若一个程序有多个进程同时在运行,则可共享text段

4.用户栈、运行时堆

上面高地址,下面低地址

①栈:0x7ff

②堆:0x5

栈往下涨,堆往上涨

栈底其实是在天花板上,堆底在下面

这样,栈和堆有一部分空间可以共用,谁需要就谁占用。栈和堆对着长。栈在上,往下长。堆在下,往上涨。

计算机中存放地址都是用16进制

0x38到0x40中间是8B,不是2B:38 39 3a 3b 3c 3d 3e 3f 40

(1)栈区

栈帧。当被调函数执行结束,栈帧上的变量也会被自动回收。

调用,压栈(在栈中压入一个栈帧)

栈帧后进先出,调用函数时压栈,函数返回时弹栈。

(2)堆区 (自由存储区)

new出来的,不会自动销毁。需要手动回收,否则会发生内存泄漏。

(3)指针和引用

①指针(间接访问 值传递)

1.* 取内容(间接访问)

  1. &取地址

3.->运算符

若p为指针,则(*p).memberp->member等价

②引用(引用传递)

引用,&x,&y就是给变量x,y起了个别名,并没有新开辟内存存储空间。这样,被调函数的参数列表(int &x, int &y)就可以直接引用传递给主函数中的变量x,y。因为&x &y与x y 享有同一个内存地址,会直接修改。

C++引用,底层是靠指针实现的


C++的两种传递方式:值传递、引用传递

例1:变量名-直接访问-值传递:在被调函数中无法修改主调函数中参数的内容。尽管变量名相同,但不是同一个地址

cpp 复制代码
#include <cstdio>

void swap1(int x,int y){
	int temp = x;
	x = y;
	y = temp;
}

int main(){
	int x = 1 ,y = 2;
	swap1(x,y);
}

结果是,在swap1中x与y的值互换了,但main中的x与y的值不变。因为swap1中和main中的x、y的地址不同。

例2:指针-间接访问-值传递

在被调函数里改变主调函数中变量的内容:传指针(间接访问)

在普通函数中想要改变main函数中的值,要传指针。值才能透出去。

cpp 复制代码
#include <cstdio>

void swap2(int *px,int *py){
	int temp = *px;
	*px = *py;
	*py = temp;
}

int main(){
	int x = 1 ,y = 2;
	int *px = &x;
	int *py = &y;
	swap2(px,py);
}

例3:引用-引用传递

对比例1,只修改了被调函数的参数列表,将int x,int y改为 int &x,int &y

cpp 复制代码
#include <cstdio>

void swap3(int &x,int &y){ 
    int temp = x;
    x = y;
    y = temp;
}

int main(){
    int x = 1 ,y = 2;
    swap3(x,y);
}

2.二叉树

1 << i:1左移i位,为2的i次方

cpp 复制代码
#include <iostream>
#include <cmath>
using namespace std;

int main() {
    int i = pow(2,5);  //2的5次方
    cout << "i = " << i << endl;
    int j = 1 << 5;   //2的5次方
    cout << "j = " << j << endl;
    return 0;
}

(1)二叉树的存储

顺序存储

链式存储

(2)二叉树的遍历

①递归遍历:前中后序遍历 (深度优先)
②层次遍历:队列 (广度优先)
③重建二叉树,并遍历
④申请一个新的树结点

(3)例题

例题1:二叉树遍历(难度:中等)

提交网址:https://www.nowcoder.com/share/jump/2891302591709467187427

题目要求:根据有#的先序遍历序列,构建二叉树,并输出中序遍历序列 (清华复试上机真题)

24机试指南炉灰老师

关键思路:利用分治法,递归建树

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

struct TreeNode{
    char data;
    struct TreeNode *left,*right;
};

TreeNode * RecursiveBuildTree(int &i,string str){
    char c = str[i];
    ++i;
    if(c == '#'){
        return NULL;
    }else{
        TreeNode *newNode = new TreeNode;
        newNode->data = c;
        newNode->left  = RecursiveBuildTree(i,str);
        newNode->right = RecursiveBuildTree(i,str);
        return newNode;
    }
}

void InOrder(TreeNode *T){
    if(T != NULL){
        InOrder(T->left);
        cout << T->data <<" ";
        InOrder(T->right);
    }
}

int main() {
    string str;
    while(cin >> str){
        int i = 0;
        TreeNode *root = RecursiveBuildTree(i,str);
        InOrder(root);
        cout << endl;
    }
    return 0;
}
例题2:二叉树遍历/重建二叉树 (难度:中等)

提交网址:http://t.cn/AiKgDfLU

题目要求:通过先序序列和中序序列建立二叉树,再输出后序遍历序列(华科复试上机真题)

思路:利用二叉树左右子树的特性,分治法递归重新建树

C++版本:

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

struct TreeNode{
    char data;
    TreeNode *left,*right;
};

//递归重建二叉树
TreeNode *ReBuild(string PreOrder,string InOrder){
    if(PreOrder.size() == 0)    return NULL;
    char rootdata = PreOrder[0];
    TreeNode *newNode = new TreeNode;  //申请一个新的树结点
    newNode->data = rootdata;          //数据域
    int pos = InOrder.find(rootdata); //pos为中序遍历中根结点的位置
    //左子树: 左子树先序遍历序列:PreOrder.substr(1,pos)   左子树中序遍历序列:InOrder.substr(0,pos)
    //右子树: 右子树先序遍历序列:PreOrder.substr(pos+1)   右子树中序遍历序列:InOrder.substr(pos+1)
    newNode->left  = ReBuild(PreOrder.substr(1,pos),InOrder.substr(0,pos));
    newNode->right = ReBuild(PreOrder.substr(pos+1),InOrder.substr(pos+1));
    return newNode;
}

//后序遍历
void PostOrder(TreeNode *T){
    if(T != NULL){
        PostOrder(T->left);
        PostOrder(T->right);
        cout << T->data;
    }
}

int main() {
    string PreOrder,InOrder;
    while(cin >> PreOrder >> InOrder){
        TreeNode * root = ReBuild(PreOrder,InOrder);
        PostOrder(root);
        cout << endl;
    }
    return 0;
}

C语言版本:

cpp 复制代码
#include <cstdio>
#include <string>
using namespace std;

struct TreeNode{
    char data;
    TreeNode * leftChild;
    TreeNode * rightChild;
};

TreeNode *rebuild(string preOrder,string inOrder){ //返回值为子树根结点的地址
    if(preOrder.size() == 0){
        return NULL;
    }else{
        //从先序遍历确定根
        char rootdata = preOrder[0];
        TreeNode *pNewNode = new TreeNode;//二叉树结点指针
        pNewNode->data = rootdata;
        //用根位置切割中序
        int pos = inOrder.find(rootdata);//pos是根在中序序列中出现的下标
        pNewNode->leftChild = rebuild(preOrder.substr(1,pos),inOrder.substr(0,pos));
        pNewNode->rightChild = rebuild(preOrder.substr(pos+1),inOrder.substr(pos+1));
        return pNewNode;
    }
}

void PostOrder(TreeNode * root){
    if(root == NULL){
        return;
    }
    PostOrder(root->leftChild);
    PostOrder(root->rightChild);
    printf("%c",root->data);
    return;
}

int main(){
    char preOrder[30];
    char inOrder[30];
    while(scanf("%s%s",preOrder,inOrder) != EOF){
        TreeNode * root = rebuild(preOrder,inOrder);
        PostOrder(root);
        printf("\n");
    }
}

3.二叉排序树 BST

(1)BST的建立 (双指针法)

二叉排序树(二叉搜索树,二叉查找树,Binary Search Tree,BST) 的建立。

current、parent 双指针法

cpp 复制代码
#include <iostream>
using namespace std;

struct BinaryTree{
    int data;
    BinaryTree *left,*right;
};

//BST建树,插入结点
void InsertBinary(BinaryTree * &root,int data){
    BinaryTree *Node = new BinaryTree;  
    Node->data = data,Node->left = NULL,Node->right = NULL;
    if(root == NULL){
        root = Node;
        return;
    }else{
        BinaryTree *current = root, *parent = NULL;
        while(current != NULL){
            parent = current;
            if(data < current->data){
                current = current->left;
            }else{
                current = current->right;
            }
        }
        //跳出while,说明current为空,将新结点Node插入
        if(data < parent->data){
            parent->left = Node;
        }else{
            parent->right = Node;
        }
        return;
    }
}

int main() {
    BinaryTree *root = NULL;
    int data;
    int n;
    cin >> n;
    for(int i = 0; i < n; ++i){
        cin >> data;
        InsertBinary(root,data);
    }
    return 0;
}

(2)例题

例题1:二叉排序树 (难度:简单-中等)

华科 KY207 二叉排序树

提交网址:http://t.cn/Ai9PAkkv

提交网址:https://www.acwing.com/problem/content/3598/

1.Edward非递归版本:双指针法 (current,parent)

cpp 复制代码
#include <iostream>
using namespace std;

struct BinaryTree{
    int data;
    BinaryTree *left,*right;
};

void InsertBST(BinaryTree * &root,int data){
    //申请一个新的树结点,并初始化
    BinaryTree * Node = new BinaryTree;
    Node->data = data;
    Node->left = NULL;
    Node->right = NULL;
    //对传进来的结点进行判断
    if(root == NULL){  //第一次传进来,是根节点
        cout << -1 << endl;
        root = Node; //修改根节点
        return;
    }else{
        //双指针法
        BinaryTree * current = root;
        BinaryTree * parent = NULL;
        while(current != NULL){
            parent = current;  //下移前,cur将值保存给parent
            if(current->data > data){ //当前结点值 大于 要插入的结点值
                current = current->left;  //向左走
            }else{
                current = current->right;
            }
        }
        //curent走到空,将新结点插入
        if(data < parent->data){
            parent->left = Node;
        }else{
            parent->right = Node;
        }
        cout << parent->data << endl;
        return;
    }
}

int main(){
    int n;
    cin >> n;
    int data;
    BinaryTree * root = NULL;
    for(int i = 0; i < n; ++i){
        cin >> data;
        InsertBST(root,data);
    }
    return 0;
}

2.2024泥鳅老师版本(我觉得while、if、else部分太冗长,代码结构不清晰)

cpp 复制代码
#include <iostream>
using namespace std;

struct TreeNode{
    int data;
    TreeNode *left,*right;
};

//二叉树结点的插入
void InsertBST(TreeNode * &proot,int data){
    TreeNode *pNew = new TreeNode; //申请一个新结点
    pNew->data = data;
    pNew->left = NULL;
    pNew->right = NULL;
    if(proot == NULL){
        proot = pNew;
        cout << -1 << endl;
    }else{
        TreeNode *pCur = proot; //pCur向下探索
        TreeNode *pPre; //pPre指向pCur的父结点
        while(1){
            if(pCur->data > data){  //当前结点值 大于 要插入的结点值
                pPre = pCur;
                pCur = pCur->left;  //向左走
                if(pCur == NULL){
                    pPre->left = pNew; //左孩子置为新结点
                    cout << pPre->data << endl;
                    break;
                }
            }else{ //当前结点值 小于 要插入的结点值
                pPre = pCur;
                pCur = pCur->right;  //往右走
                if(pCur == NULL){
                    pPre->right = pNew;
                    cout << pPre->data << endl;
                    break;
                }
            }
        }
    }
}

int main() {
    int n;
    cin >> n;
    TreeNode * proot = NULL;
    int data;
    for(int i = 0; i < n; ++i){
        cin >> data;
        InsertBST(proot,data);
    }
    return 0;
}
例题2:二叉搜索树 (难度:中等-困难)

浙大 判断是否为同一个二叉搜索树序列

提交网址:http://t.cn/Ai9PUJtK

思路:①BST建树 ②比较前序遍历、中序遍历

(思路比较简单,处理数据很麻烦)

cpp 复制代码
//判断两BST是否相同
#include <iostream>
#include <string>
using namespace std;

struct BinaryTree{
    char data;
    BinaryTree *left,*right;
};

//BST建树,插入结点
void InsertBinary(BinaryTree * &root,int data){
    BinaryTree *Node = new BinaryTree;
    Node->data = data,Node->left = NULL,Node->right = NULL;
    if(root == NULL){
        root = Node;
        return;
    }else{
        BinaryTree *current = root, *parent = NULL;
        while(current != NULL){
            parent = current;
            if(data < current->data){
                current = current->left;
            }else{
                current = current->right;
            }
        }
        //跳出while,说明current为空,将新结点Node插入
        if(data < parent->data){
            parent->left = Node;
        }else{
            parent->right = Node;
        }
        return;
    }
}

//前序遍历
void PreOrder(BinaryTree *root,string &preorder){
    if(root != NULL){
        preorder += root->data;
        PreOrder(root->left,preorder);
        PreOrder(root->right,preorder);
    }
}

//中序遍历
void InOrder(BinaryTree *T,string &inorder){
    if(T != NULL){
        InOrder(T->left,inorder);
        inorder += T->data;
        InOrder(T->right,inorder);
    }
}

int main() {
    char data;
    int n;
    while(cin >> n){
        if(n == 0)  break;
        //读取字符串,建树
        string str;
        cin >> str;
        BinaryTree *root = NULL;
        for(int i = 0; i < str.size();++i){
            InsertBinary(root,str[i]);
        }
        //原树的先序,中序
        string preorder1 = "",inorder1  = "";
        PreOrder(root,preorder1);
        InOrder(root,inorder1);
        //n次对比
        for(int i = 0; i < n; ++i){
            string str2;
            cin >> str2;
            BinaryTree *root2 = NULL;
            for(int i = 0; i < str2.size();++i){  //分别建树
                InsertBinary(root2,str2[i]);
            }
            string preorder2 = "",inorder2  = "";
            PreOrder(root2,preorder2);
            InOrder(root2,inorder2);
            if(preorder1 == preorder2 && inorder1 == inorder2)  cout << "YES" << endl;
            else                                                cout << "NO"  << endl;
        }
    }
    return 0;
}

4.优先队列 priority_queue

(1)概念

1.

优先队列不是队列(queue)而是堆(heap),是二叉堆(大根堆、小根堆),结构是完全二叉树,用数组保存。

2.大根堆

优先队列默认为大根堆。

特点:

①队列:先进先出

②优先队列:出最大的

cpp 复制代码
priority_queue<typename> name;

3.小根堆 (重新定义优先队列)

cpp 复制代码
priority_queue <typename,vector<typename>, greater<typename> > name

(2)优先队列模板 STL-priority_queue

1.定义

cpp 复制代码
#include <queue>
using namespace std;

priority_queue<typename>name;

2.增删元素

入队 :插入元素 push()

出队 :删除元素,出最大值 pop()

3.元素访问
队首 :只能访问优先级最高的元素 top()

4.状态

队空 :是否为空 empty()

队长 :元素个数 size()

5.测试

cpp 复制代码
#include <iostream>
#include <queue>
using namespace std;

int main(){
    int arr[6] = {2,4,6,1,3,5};
    priority_queue<int> myPQ;
    for(int i = 0; i < 6; ++i){
        myPQ.push(arr[i]);
        cout << "top = " << myPQ.top() << endl;
    }
    cout << "-------------------" << endl;
    while(!myPQ.empty()){
        cout << "pop,top = " << myPQ.top() << endl;
        myPQ.pop();
    }
    return 0;
}

(3)例题

例题1:复数集合 (难度:中等)

提交网址:http://t.cn/Ai98yYlt

注意:1+i2,应该用scanf读取 ,很难用cin读取。scanf("%d+i%d", &re, &im);

cpp 复制代码
#include <iostream>
#include <queue>
#include <cmath>
#include <string>
using namespace std;

//复数
struct Complex{
    //数据成员
    int realpart;
    int imaginarypart;
    //含参构造函数,简化初始化过程
    Complex(int re,int im){
        realpart = re;
        imaginarypart = im;
    }
};

//重载运算符
bool operator < (Complex lhs,Complex rhs){
    return pow(lhs.realpart,2) + pow(lhs.imaginarypart,2) < pow(rhs.realpart,2)+pow(rhs.imaginarypart,2);
}

int main() {
    int n;
    cin >> n;
    priority_queue<Complex> myPQ;
    for(int i = 0; i < n; ++i){
        string action;
        cin >> action;
        if(action == "Pop"){
            if(myPQ.empty()){
                cout << "empty" << endl;
            }else{
                cout << myPQ.top().realpart <<"+i" << myPQ.top().imaginarypart << endl;
                myPQ.pop();
                cout << "SIZE = " << myPQ.size() << endl;
            }
        }else if(action == "Insert"){
            int re,im;
            //cin >> re >> im;  //注意,读取 1+i2,应该用scanf控制格式
            scanf("%d+i%d", &re, &im);
            Complex c(re,im);
            myPQ.push(c);
            cout << "SIZE = "<<myPQ.size() << endl;
        }
    }
    return 0;
}

提交网址:https://www.acwing.com/problem/content/3542/

多加了一个条件,模相等时,输出较小的虚数

cpp 复制代码
//重载运算符
bool operator < (Complex lhs,Complex rhs){
    if(pow(lhs.realpart,2) + pow(lhs.imaginarypart,2) == pow(rhs.realpart,2)+pow(rhs.imaginarypart,2)){
        return lhs.imaginarypart > rhs.imaginarypart;  //模相等,输出较小的虚数
    }else{
        return pow(lhs.realpart,2) + pow(lhs.imaginarypart,2) < pow(rhs.realpart,2)+pow(rhs.imaginarypart,2);
    }
}
例题2:哈夫曼树(难度:简单)

哈夫曼树

1.求WPL(带权路径和)

①构建哈夫曼树,再求WPL:已掌握

②迭代式求WPL

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

提交网址:http://t.cn/AiCuGMki

提交网址:https://www.acwing.com/problem/content/description/3534/


思路:

①用优先队列(取相反数)凑成小根堆

②哈夫曼树WPL = Σ叶结点权值×边数 = 非叶结点权值之和 = 除根结点外所有结点的权值之和

cpp 复制代码
#include <iostream>
#include <queue>
using namespace std;

int main() {
    priority_queue<int> myPQ; //大根堆变小根堆:存储权值的相反数
    int n,weight;
    cin >> n;
    for(int i = 0; i < n; ++i){
        cin >> weight;
        myPQ.push(-1 * weight);
    }
    int WPL = 0;
    while(myPQ.size() >= 2){
        int leaf1 = myPQ.top();
        myPQ.pop();
        int leaf2 = myPQ.top();
        myPQ.pop();
        WPL += leaf1 + leaf2;
        myPQ.push(leaf1 + leaf2);
    }
    cout << -1*WPL << endl;
    return 0;
}

5.散列表 map

(1)映射 map

1.map底层:红黑树 (RBT∈BST),

2.特点:所以map会自动排好序 (BST中序遍历是升序序列)。

3.map查找:时间复杂度 O(logn) (和二分查找相同的时间复杂度,但比二分查找需要更多的空间)

4.操作

(1)头文件

cpp 复制代码
#include <map>
using namespace std;

定义

cpp 复制代码
map<string,int> myMap;

初始化:

cpp 复制代码
map<string,int> myMap = {
	{"Caixukun",1},
	{"Wuyifan",2},
	{"Liyifeng",3}
};

(2)插入键值对

insert()方法

cpp 复制代码
myMap.insert(pair<string,int>("Wuyifan",2));

pair头文件 #include <utility>

[]下标访问运算符

cpp 复制代码
myMap["Caixukun"] = 1;

删除键值对:erase()

cpp 复制代码
myMap.erase("Wuyifan");

读取键对应的值:

(3)判空:empty()

求长度(获取键值对个数):size()

(4)map的遍历:迭代器 iterator (迭代器是指向内部元素的指针)

①定义迭代器:map<string,int>::iterator it;

②第一个成员的位置:.begin()

③尾后位置:.end()

④迭代器指针后移:++it   (++it使得迭代器指针指向下一对键值对,unorder_map不支持此操作)

⑤键:it->first

⑥值:it->second

cpp 复制代码
map<string,int>::iterator it;
for(it = myMap.begin();it != myMap.end();++it){
	printf("%s %d\n",it->first.c_str(),it->second);
}

(5)查找某个键是否存在:find()函数

(6)map从大到小排序

map默认从小到大排序,若要使得map降序排序,需要加入greator<key数据类型>

cpp 复制代码
map<int,string,greater<int>> myMap;

(7)map[i]++

①若map中没有key为i的值,则先insert <i,0>,然后value++。最终map中存入<i,1>。

②若map中已有key = i,则value++

cpp 复制代码
#include <cstdio>
#include <map>
#include <iostream>
using namespace std;

int main() {
    map<int, int> myMap;
    for (int i = 0; i < 5; i++) {
        myMap[i]++;
    }
    for (auto it = myMap.begin(); it != myMap.end(); it++) {
        cout << '<'<< it->first << ',' << it->second <<'>'<< endl;
    }

    cout<<"第二轮"<<endl;
    for (int i = 0; i < 5; i++) {
        myMap[i]++;
    }
    for (auto it = myMap.begin(); it != myMap.end(); it++) {
        cout << '<'<< it->first << ',' << it->second <<'>'<< endl;
    }
    return 0;
}

(8)map举例:

cpp 复制代码
#include <cstdio>
#include <string>
#include <map>
using namespace std;

int main(){
    //键 key --> 值 value
    //<键的类型,值的类型>
    map<string,string> myMap = {
            {"Caixukun","ikun"},
            {"Wuyifan","meigeni"}
    };
    char str[1000];
    scanf("%s",&str);
    string name = str;
    printf("%s的粉丝被称为%s",name.c_str(),myMap[name].c_str());
}

(2)例题

例题1:查找学生信息

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

提交网址:http://t.cn/AiCuVIuY

cpp 复制代码
#include <cstdio>
#include <string>
#include <map>
using namespace std;

struct Student{
    string name;
    string gender;
    int age;
};

int main(){
    int n;
    scanf("%d",&n);
    map<string,Student> InfoMap;
    for(int i = 0; i < n; ++i){
        char num[30];
        char name[30];
        char gender[30];
        int age;
        scanf("%s %s %s %d",num,name,gender,&age);
        //key string
        string numstr = num;
        //value Student
        Student student;
        student.name = name;
        student.gender = gender;
        student.age = age;
        InfoMap[numstr] = student;
    }
    int m;
    scanf("%d",&m);
    for(int i = 0; i < m; ++i){
        char num[30];
        scanf("%s",num);
        string numstr = num;
        if(InfoMap.find(numstr) != InfoMap.end()){//找到了
            printf("%s %s %s %d\n",numstr.c_str(),
                   InfoMap[numstr].name.c_str(),
                   InfoMap[numstr].gender.c_str(),
                   InfoMap[numstr].age);
        }else{//学号没找到
            printf("No Answer!\n");//这里漏加换行符\n,导致格式错误了好几次。
        }
    }
}
例题2:魔咒词典

例题2:魔咒词典 (浙大上机复试真题)

提交网址:http://t.cn/AiCufczt

cpp 复制代码
#include <cstdio>
#include <string>
#include <map>
using namespace std;

//魔咒词典  (采用 增量编辑法:即写一部分,测试一部分)
int main(){
    map<string,string> dict;
    while(true){
        char line[200];
        fgets(line,200,stdin);//输入一行
        string linestr = line;
        linestr.pop_back();//干掉回车,string最后一个字符为\n
        if("@END@" == linestr){
            break;
        }
//        printf("%s\n",linestr.c_str());
        int pos = linestr.find("]");
        string word = linestr.substr(0,pos+1);
        string info = linestr.substr(pos+2);
//        printf("word = %s, info = %s\n",word.c_str(),info.c_str());
        dict[word] = info;
        dict[info] = word;
    }

    int n;
    scanf("%d",&n);
    getchar();//吃掉回车 ※
    for(int i = 0 ; i < n; ++i){
        char line[200];
        fgets(line,200,stdin);
        string linestr = line;
        linestr.pop_back();

        if(dict.find(linestr) != dict.end()){//存在魔咒或功能
            if('[' == linestr[0]){//输入魔咒,查找功能
                printf("%s\n",dict[linestr].c_str());
            }else{//输入功能查找魔咒
                string charm = dict[linestr];//[xxxxxx],想办法去掉[]
                string charm_sub = charm.substr(1,charm.size()-2);//取子串,去掉了[]
                printf("%s\n",charm_sub.c_str());
            }
        }else{//不存在该魔咒或功能
            printf("what?\n");
        }
    }
}

(3)unorder_map 哈希表

1.底层:HashTable 散列表

2.unorder_map查找 :时间复杂度O(1)

3.特点:①空间特别大 ②无序,不能遍历

第8章 搜索

搜索问题,就是带有限制的枚举问题。



1.BFS 广度优先搜索

(1)概念

1.名词解释:

BFS,Breadth-First-Search,广度优先搜索(宽度优先搜索)

2.方法:

广度优先搜索,类似层序遍历,把距离为1的结点都访问一遍才走下一层。稳扎稳打,瞻前顾后

3.数据结构:队列

4.目的:为了求最优解问题

(2)例题

例题1:树的高度

提交网址:https://www.acwing.com/problem/content/3702/ [南京理工大学复试上机题]

例题2:玛雅人的密码 (BFS)

提交网址:https://www.acwing.com/problem/content/3388/

提交网址:http://t.cn/Ai0lUhJj

答案:

例题3:Catch that Cow
例题4:Find the Multiple

(3)打表

当OJ时限很小,且输入范围有限(1≤n≤200)


还是上文例题2:Find the Multiple,用打表法解决


2.DFS 深度优先搜索

(1)概念

1.概念:

DFS,Depth-First-Search,深度优先搜索。

2.目的:

判断问题是否有解,例如找迷宫出口。不拥有最优解的特性。

3.实现:

递归 实现,不需要数据结构。因此DFS代码比BFS代码要简单一些。

②DFS也可以用实现

4.特点:

一条路走到黑,撞到南墙才回头


(2)例题

例题1:八皇后问题

提交网址:https://www.acwing.com/problem/content/3475/


例题2:数组划分

提交网址:https://www.acwing.com/problem/content/3506/

答案:

剪枝答案:

例题3:A Knight's Journey
例题4:Square

(3)剪枝算法

在DFS搜索过程中,可以通过放弃对某些不可能产生结果的子集的搜索,以提高效率。这样的算法称为剪枝。

相关推荐
暮色_年华10 分钟前
Modern Effective C++item 9:优先考虑别名声明而非typedef
c++
重生之我是数学王子18 分钟前
QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
开发语言·c++·qt
我们的五年42 分钟前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
做人不要太理性1 小时前
【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!
c++·哈希算法·散列表·unordered_map·unordered_set
程序员-King.1 小时前
2、桥接模式
c++·桥接模式
chnming19871 小时前
STL关联式容器之map
开发语言·c++
程序伍六七2 小时前
day16
开发语言·c++
小陈phd2 小时前
Vscode LinuxC++环境配置
linux·c++·vscode
火山口车神丶2 小时前
某车企ASW面试笔试题
c++·matlab
是阿建吖!3 小时前
【优选算法】二分查找
c++·算法