尚未理解树以前感受树很神秘(看过数据结构视频),树这种结构看上去很难以想象,究竟是怎么实现而且操做的,学完二叉树就感受这操做有点简单。巧妙经过递归就把对树杈的处理变成了对根和左右孩子的处理。 树能够处理大量的数据,可是对数的操做代码量很少,由于大部分操做使用了递归,须要对递归有较好的理解,不然代码很容易出现错误,并且很难发现。 树这个数据结构很是实用,因此必需要掌握,好比目录,排序等都须要树,acm也会出现树的题目。
建表达式树使用两个栈分别放树和运算符,遍历放表达式的字符串,遇到数字就建一个节点入栈,若是是运算符就要判断是否优先级,若是比栈顶小,栈顶就能够拿出来,用该运算符建一个节点,左右孩子为树栈最上面的两个节点。计算表达式,经过树的后续遍历就能够。
void InitExpTree(BTree &T, string str) { 声明两个栈,一个树栈,一个运算符栈 Chsta.push('#')运算符栈入栈一个#号避免为空 for (遍历字符串str) { if (若是是数字) { 建节点 Bt->data = str[i] 左右孩子置为空 Bt->lchild = Bt->rchild = NULL 入树栈 BTsta.push(Bt) } else 若是是运算符 { 调用Precede函数比较优先级 char result = Precede(Chsta.top(), str[i]); if (若是比运算符栈栈顶大) { 入栈 Chsta.push(str[i]); } else if (若是相等)说明是括号 { 出栈 Chsta.pop(); } else 若是比运算符栈栈顶小 { 用运算符建一个节点 Bt->data = Chsta.top(); Chsta.pop(); 左右孩子为树栈顶的两个 Bt->rchild = BTsta.top(); BTsta.pop(); Bt->lchild = BTsta.top(); BTsta.pop(); 最后入栈 BTsta.push(Bt); } } } while (运算符栈还有运算符) { 用运算符建一个节点 Bt->data = Chsta.top(); Chsta.pop(); 左右孩子为树栈顶的两个 Bt->rchild = BTsta.top(); BTsta.pop(); Bt->lchild = BTsta.top(); BTsta.pop(); 最后入栈 BTsta.push(Bt); } } double EvaluateExTree(BTree T) { double left, right放左孩子和右孩子 if (T == NULL) { return 0; } if (若是是叶子节点) { return T->data-'0' 返回节点值 } 递归左孩子 left = EvaluateExTree(T->lchild); 递归右孩子 right = EvaluateExTree(T->rchild); 计算 switch (T->data) // 根据b结点作相应运算 { case '+': return left + right; case '-': return left - right; case '*': return left * right; case '/': if (right != 0) return left / right; else { cout<<"divide 0 error!"; // 除0异常退出 exit(0); } } }
Q:没有考虑括号两个括号相遇时要出栈ios
该题是应用并查集,每一个俱乐部的成员和该俱乐部第一个成员合并,最后哈希获得最大的朋友圈人数,为了减小查找时间,尽力让节点指向根。
#include <iostream> using namespace std; int stu[30010]定义全局变量 int Find(int x) { if (若是x等于stu[x])说明根是本身 { 返回 stu[x]; } else 继续递归找根 { return stu[x]=Find(stu[x]);尽可能让节点指向根 } } void add(int a, int b)将a和b合并 { int x = Find(a);查找根 int y = Find(b);查找根 if (x != y)合并 { stu[x] = y; } } int main() { int N, M; cin >> N >> M; for (int i = 1; i <= N; i++) 并查集初始化,根是本身 { stu[i] = i; } for (int i = 0; i < M; i++) { int count,a; cin >> count >> a; int b; for (int j = 0; j < count - 1; j++) { cin >> b; add(a, b);//调用合并函数 } } int max = 0; int myhash[30010] = { 0 };hash求最大朋友圈人数 for (int i = 1; i <= N; i++) { int temp = Find(i);找根 myhash[temp]++;根同样加一 if (myhash[temp] > max)找最大值 { max = myhash[temp]; } } cout << max; return 0; }
Q:在递归时尽可能让节点都指向根数据结构
这个就是一个哈夫曼树,使用multiset(set不能存放多个相同数据),multiset是从小到大排序好的,每次取最小两个数据相加,而后做为新的元素加入multiset中(固然这两个得删除),直到只剩一个数据,用sum记录全部相加和,sum即为所求最小花费。
A:此题难点不是在于代码,而是思路,当时恰好学完哈夫曼树,而后又有STL的加持,就会显得很轻松就过。ide
题目描述函数
在桌面上有一排硬币,共NN枚,每一枚硬币均为正面朝上。如今要把全部的硬币翻转成反面朝上,规则是每次可翻转任意N-1N−1枚硬币(正面向上的被翻转为反面向上,反之亦然)。求一个最短的操做序列(将每次翻转N-1枚硬币成为一次操做)。学习
输入输出格式lua
输入格式:
一个天然数NN(NN为不大于100100的偶数)。spa
输出格式:
第一行包含一个整数SS,表示最少须要的操做次数。接下来的SS行每行分别表示每次操做后桌上硬币的状态(一行包含NN个整数(00或11),表示每一个硬币的状态:00――正面向上,和11――反面向上,不容许出现多余空格)。设计
对于有多种操做方案的状况,则只需字典序最小输出一种。指针
输入输出样例code
输入样例#1: 复制
4
输出样例#1: 复制
4
0111
1100
0001
1111
翻n-1枚硬币,就是有一枚不翻,也能够理解为翻一枚
逻辑性的题目通常能够找出规律性,看上去可能很麻烦可是能够其实代码量不多,或者有时候能够巧妙地借助STL完成解题。