陈越《数据结构》第七讲 图(中)一
来源:互联网 发布:ps怎么装磨皮软件 编辑:程序博客网 时间:2024/06/05 05:30
Tree Traversals Again
1086.Tree Traversals Again (25)
An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For example, suppose that when a 6-node binary tree (with the keys numbered from 1 to 6) is traversed, the stack operations are: push(1); push(2); push(3); pop(); pop(); push(4); pop(); pop(); push(5); push(6); pop(); pop(). Then a unique binary tree (shown in Figure 1) can be generated from this sequence of operations. Your task is to give the postorder traversal sequence of this tree.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (<=30) which is the total number of nodes in a tree (and hence the nodes are numbered from 1 to N). Then 2N lines follow, each describes a stack operation in the format: “Push X” where X is the index of the node being pushed onto the stack; or “Pop” meaning to pop one node from the stack.
Output Specification:
For each test case, print the postorder traversal sequence of the corresponding tree in one line. A solution is guaranteed to exist. All the numbers must be separated by exactly one space, and there must be no extra space at the end of the line.
Sample Input:
6
Push 1
Push 2
Push 3
Pop
Pop
Push 4
Pop
Pop
Push 5
Push 6
Pop
Pop
Sample Output:
3 4 2 6 5 1
题目大意:
用栈的形式给出一棵二叉树的建立的顺序,求这棵二叉树的后序遍历
分析:栈实现的是二叉树的中序遍历(左根右),而每次push入值的顺序是二叉树的前序遍历(根左右),所以该题可以用二叉树前序和中序转后序的方法做~~
#include <cstdio>#include <stack>using namespace std;int preorder[35], inorder[35];int n, preid = 0, inid = 0, cnt = 0;int get(){ char s[10]; scanf("%s", s); if (s[1] == 'o') return -1; int a; scanf("%d", &a); return a;}void build(int preb, int pree, int inb, int ine){ if (preb > pree) return; int root = preorder[preb]; int inroot = inb; while (inorder[inroot] != root) ++inroot; build(preb+1, preb+inroot-inb, inb, inroot-1); build(preb+inroot-inb+1, pree, inroot+1, ine); if (cnt++ != 0) putchar(' '); printf("%d", root);}int main(){ scanf("%d", &n); stack<int> st; for (int i = 0; i < n*2; ++i){ int a = get(); if (a != -1){ st.push(a); preorder[preid++] = a; }else{ inorder[inid++] = st.top(); st.pop(); } } build(0, n-1, 0, n-1); return 0;}
Complete Binary Search Tree
A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:
The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
Both the left and right subtrees must also be binary search trees.
A Complete Binary Tree (CBT) is a tree that is completely filled, with the possible exception of the bottom level, which is filled from left to right.
Now given a sequence of distinct non-negative integer keys, a unique BST can be constructed if it is required that the tree must also be a CBT. You are supposed to output the level order traversal sequence of this BST.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (<=1000). Then N distinct non-negative integer keys are given in the next line. All the numbers in a line are separated by a space and are no greater than 2000.
Output Specification:
For each test case, print in one line the level order traversal sequence of the corresponding complete binary search tree. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.
Sample Input:
10
1 2 3 4 5 6 7 8 9 0
Sample Output:
6 3 8 1 5 7 9 0 2 4
题意:
给一串构成树的序列,已知该树是完全二叉搜索树,求它的层序遍历的序列
分析:
总得概括来说,已知中序,可求root下标,可以求出层序。
1. 因为二叉搜索树的中序满足:是一组序列的从小到大排列,所以只需排序所给序列即可得到中序
2. 因为根据完全二叉树的结点数,可以求出它的根结点在中序中对应的下标
3. 如此,已知了中序,又可以根据结点数求出根结点的下标,就可以递归求出左右子树的根结点的下标
4. i结点的左孩子为2 * i + 1,右孩子2 * i + 2,就可以根据结点下标和中序数组赋值level数组
5. 最后输出所有结点的层序数组level
图1
图2
图3
#include <cstdio>#include <cstdlib>#include <math.h>const int MaxNum = 1005;int node[MaxNum];int tree[MaxNum];int cmp(const void *a,const void *b){/*以图2为基准*/ int *pa = (int *)a; int *pb = (int *)b; return *pa-*pb;}int GetLeftLength(int n){/*以图3为基准*/ int h, x, l; /*转换成以2为底*/ h = log((double)(n + 1))/log (2.0); x = n + 1 - pow(2.0, h); if (x > pow(2.0, h - 1)) { x = pow(2.0, h - 1); } l = pow(2.0, h - 1) - 1 + x; return l;}void solve(int ALeft, int ARight, int TRoot){/*初始调用为solve(0,N-1,0)*//*以图1为基准*/ int n,L,LeftTRoot,RightTRoot; n = ARight - ALeft + 1; if(n==0) return; /*考虑完美二叉树的情况*/ L = GetLeftLength(n); /*计算出n个节点的树,其左子树有多少个节点*/ tree[TRoot] = node[ALeft + L]; LeftTRoot = TRoot * 2 + 1; RightTRoot = LeftTRoot + 1; solve(ALeft, ALeft + L -1, LeftTRoot); solve(ALeft + L + 1, ARight , RightTRoot);}int main(){ int i,n; /*输入*/ scanf("%d",&n); for(i=0;i<n;++i){ scanf("%d",&node[i]); } /*从大到小排序*/ qsort(node,n,sizeof(int),cmp); /*排序成完全二叉树*/ solve(0,n-1,0); /*输出*/ printf("%d",tree[0]); for(i=1;i<n;++i){ printf(" %d",tree[i]); } printf("\n"); system("pause"); return 0;}
Huffman Codes
PTA - Data Structures and Algorithms (English) - 5-9
In 1953, David A. Huffman published his paper “A Method for the Construction of Minimum-Redundancy Codes”, and hence printed his name in the history of computer science. As a professor who gives the final exam problem on Huffman codes, I am encountering a big problem: the Huffman codes are NOT unique. For example, given a string
Input Specification:
Each input file contains one test case. For each case, the first line gives an integer N
where
where
Output Specification:
For each test case, print in each line either “
Note: The optimal solution is
Sample Input:
7 //结点数目num
A 1 B 1 C 1 D 3 E 3 F 6 G 6 //每个结点数据data及出现的次数weight
4 //测试数据的组数checkNum
A 00000 //之后的 4*7行 是结点数据ch及其编码s
B 00001
C 0001
D 001
E 01
F 10
G 11
A 01010
B 01011
C 0100
D 011
E 10
F 11
G 00
A 000
B 001
C 010
D 011
E 100
F 101
G 110
A 00000
B 00001
C 0001
D 001
E 00
F 10
G 11
Sample Output:
Yes
Yes
No
No
题目分析:
这是一道考察“哈夫曼编码”的问题,但是这里不一定非要把哈夫曼树构造出来。Note: The optimal solution is not necessarily generated by Huffman algorithm
- 输入:第一行是结点数目num;第二行是每个结点数据data及出现的次数weight;第三行是测试数据的组数checkNum;第四行及以后是结点数据ch及编码s。
输出:对于每一组测试数据,输出编码是否符合“哈夫曼编码”,是则输出Yes,否则输出No。
符合“哈夫曼编码”需要符合两个条件:
①WPL最小
②编码的前缀不能是其他编码的前缀。
例1:最优编码不一定通过Huffman算法得到。给定4个字符及其出现频率:
A. A:000; B:001; C:01; D:1
B. A:10; B:11; C:00; D:01
C. A:00; B:10; C:01; D:11
D. A:111; B:001; C:10; D:1
解析:C
根据答案,画出每个答案的Huffman tree,再一个个的对答案是否正确。
例2:Huffman Codes的特点:
- 最优编码 —— 总长度(WPL)最小;
- 无歧义解码 —— 前缀码:数据仅存于叶子结点;
- 没有度为1 的结点 ——
满足1、2则必然有3 。
注意:满足2、3可不一定有1 !比如:
解法:
解法转自:http://www.cnblogs.com/clevercong/p/4193370.html
1) map 用于存放:A 1 B 1 C 1 D 3 E 3 F 6 G 6 //每个结点的数据data及出现的次数(权值)weight
2) 使用C++标准库中的优先队列:priority_queue,引入头文件 #include 。优先队列底层由堆实现,数据放入队列后,会自动按照“优先级”排好顺序。
#include <map>#include <queue>map<char, int> myMap;priority_queue<int, vector<int>, greater<int> >pq; //小顶堆for(int i=0; i<num; i++) // 输入结点的数据c[i]、权值f[i]{ cin >> c[i] >> f[i]; myMap[c[i]] = f[i]; // 映射 pq.push(f[i]); // 向队列中添加元素}
3) 计算
// 计算WPL的值int myWpl = 0;while(!pq.empty()){ int myTop = pq.top(); pq.pop(); if(!pq.empty()) { int myTop2 = pq.top(); pq.pop(); pq.push(myTop + myTop2); int m = myTop + myTop2; myWpl += m; //每次加m(子节点权值重复加入) 等效于 路径长度*权值 }}
4) 测试数据需按编码排序,但标准库并没有为map制定sort函数,因此我们用vector装载pair类型,既可以模仿出map的功能,又可以用vector的排序函数。
#include <algorithm> // sort()typedef pair<char, string> PAIR; // 用PAIR来代替pair<char, string> (编码类型:string)// cmp():自定义按什么内容或大小顺序排序// 这里是按编码的长度排序int cmp(const PAIR& x, const PAIR& y){ return x.second.size() < y.second.size();}// vector + pair<,> 模仿 mapvector<PAIR> checkVec;checkVec.push_back(make_pair(ch, s)); // 向vector中添加元素sort(checkVec.begin(), checkVec.end(), cmp); // 按照编码的长度排序
5) 判断前缀问题:substr函数,取字符串中的一段并与当前编码进行比较。
bool flag = true; //已符合条件一:wpl最小for(int i=0; i<num; i++){ string tmp = checkVec[i].second; for(int j=i+1; j<num; j++) { if(checkVec[j].second.substr(0,tmp.size())==tmp) flag = false; }}
完整代码:
#include <iostream>#include <algorithm> // 排序函数 sort()#include <map>#include <queue>using namespace std;typedef pair<char, string> PAIR; // + vector来模仿 mapint cmp(const PAIR& x, const PAIR& y) // 自定义让sort()按哪种方式排序{ return x.second.size() < y.second.size();}int main(){ int num; cin >> num; char *c = new char[num]; int *f = new int[num]; map<char, int> myMap; // 用来存节点数据及权值,并构成映射 // 使用优级队列 priority_queue<int, vector<int>, greater<int> >pq; for(int i=0; i<num; i++) // 输入结点及出现次数(权值) { cin >> c[i] >> f[i]; myMap[c[i]] = f[i]; pq.push(f[i]); // 将权值压入优先队列 } // 计算WPL的值 int myWpl = 0; while(!pq.empty()) { int myTop = pq.top(); pq.pop(); if(!pq.empty()) { int myTop2 = pq.top(); pq.pop(); pq.push(myTop + myTop2); int m = myTop + myTop2; myWpl += m; } } // 输入测试数据 int checkNum; // 测试数据的组数 cin >> checkNum; for(int i=0; i<checkNum; i++) { int wpl = 0; char ch; string s; // vector + PAIR 模仿 map,使其可排序 vector<PAIR> checkVec; for(int j=0; j<num; j++) { cin >> ch >> s; checkVec.push_back(make_pair(ch, s)); // 向vector中添加测试数据及其编码 wpl += s.size() * myMap[ch]; } sort(checkVec.begin(), checkVec.end(), cmp); // 按照编码长度排序 if(wpl != myWpl) { cout << "No" << endl; continue; } else { bool flag = true; // 表示已满足条件一:wpl最小(wpl==myWpl) //条件二:编码的前缀不能是其他编码的前缀:substr() for(int i=0; i<num; i++) { string tmp = checkVec[i].second; for(int j=i+1; j<num; j++) { if(checkVec[j].second.substr(0,tmp.size())==tmp) flag = false; } } if(flag == true) cout << "Yes" << endl; else cout << "No" << endl; continue; } cout << "Yes" << endl; } return 0;}
总结的程序
#include <iostream>#include <string>using namespace std;struct Heap{ int *data; int size = 0;};struct cnode{ int tag = 0; cnode *left = nullptr; cnode *right = nullptr;};Heap *Init_Heap(int n); //初始化小根堆(利用静态链表的逻辑结构);void Insert_Heap(Heap *H, int x); //把元素依次插入小根堆;int Delmin_Heap(Heap *H); //删除小根堆中的最小元素;int Cal_Wpl(Heap *H); //计算huffman编码的wpl;int wpl_prefix(int *sample, int n, int &re); //计算待测编码的wpl及判断是否为前缀编码;/*思路:要判断是否,需要解决两个问题: 1)编码wpl等于huffman编码的wpl;2)待测编码是前缀编码。问题1: 首先要求出标准wpl。观察huffman树,我们发现其wpl是非叶子结点权值和。于是,我们无需构造出huffman树来求权值(麻烦点),通过模拟树的构造过程,理由小根堆的特点求出wpl;而待测编码的wpl就是利用每个编码的字符串长度,乘以每个字符的权值得到;问题2:思路是构造一个二叉树出来,模拟huffman树。1.让每个编码遍历树,结束时在当前结点设置标记为1;2.如果遍历时,未结束时碰到了标记为1的结点,则不是前缀编码;3.结束时,未碰到标记点(包括最后一个),是前缀编码。*/int main(){ int n, i, val; char ch; cin >> n; int *sample = new int[n]; //每个字符权值存储在这里; Heap *H = Init_Heap(n); //初始化小根堆(利用静态链表的逻辑结构); for (i = 0; i < n; i++) { cin >> ch >> val; sample[i] = val; Insert_Heap(H, val); //把元素依次插入小根堆; } int best_wpl = Cal_Wpl(H); //计算huffman编码的wpl; int m, wpl, re; //re是用来判断是否前缀编码,是为1,否为0; cin >> m; for (i = 0; i < m; i++) { wpl = wpl_prefix(sample, n, re); //计算待测编码的wpl及判断是否为前缀编码; if (wpl == best_wpl && re == 1) cout << "Yes" << endl; else cout << "No" << endl; } delete sample; return 0;}Heap *Init_Heap(int n){ Heap *H = new Heap; H->data = new int[n + 1]; //堆的下标从1开始(为了操作方便); H->data[0] = -1; //小根堆赋值最小值; return H;}void Insert_Heap(Heap *H, int x) //把元素依次插入小根堆;{ int i = ++(H->size); for (; H->data[i / 2] > x; i /= 2) //从下往上过滤; H->data[i] = H->data[i / 2]; H->data[i] = x; return;}int Delmin_Heap(Heap *H) //删除小根堆中的最小元素;{ int t = H->data[H->size--]; int min = H->data[1]; int pa, chi; for (pa = 1; pa * 2 <= H->size; pa = chi) //从上往下过滤最小元素; { chi = pa * 2; if (chi != H->size && H->data[chi + 1] < H->data[chi]) //找到子结点的最小下标; chi++; if (t < H->data[chi]) break; else H->data[pa] = H->data[chi]; } H->data[pa] = t; //赋值最小元素 return min;}int Cal_Wpl(Heap *H) //计算huffman编码的wpl;{ int sum = 0; if (H->size > 1) { int i, t1, t2, t; int m = H->size; for (i = 1; i < m; i++) { t1 = Delmin_Heap(H); //模拟构造huffman树的过程,先取出两个最小值,相加,把和插入堆中; t2 = Delmin_Heap(H); t = t1 + t2; Insert_Heap(H, t); sum += t; } } else sum = H->data[0]; return sum;}int wpl_prefix(int *sample, int n, int &re) //计算待测编码的wpl及判断是否为前缀编码;{ int i, j, len, wpl = 0; char ch; string st; cnode *phead = new cnode; cnode *p = phead; re = 1; for (i = 0; i < n; i++) { cin >> ch >> st; //此处计算wpl; len = st.length(); wpl += len*sample[i]; if (re != 0) //此处判断是否前缀编码; { for (j = 0; j < len; j++) { if (st[j] == '0') //0的话判断左边; { if (p->left == nullptr) //左边空,新建结点; { cnode *q = new cnode; p->left = q; } else { if (p->tag == 1) { re = 0; break; } } p = p->left; } else if (st[j] == '1') //判断右边; { if (p->right == nullptr) { cnode *q = new cnode; p->right = q; } else { if (p->tag == 1) { re = 0; break; } } p = p->right; } } if (p->left == nullptr && p->right == nullptr) re = 1; else re = 0; if (p->tag == 0) //注意此处需要判断,最后结点标记不为1才能赋值(待测编码有可能有相同的); p->tag = 1; else re = 0; p = phead; } } return wpl;}
- 陈越《数据结构》第七讲 图(中)一
- 陈越《数据结构》第七讲 图(中)二
- 数据结构——第七讲、图(中)(1)
- 陈越《数据结构》第四讲 树(中)
- 陈越《数据结构》第六讲 图(上)
- 读书笔记(第七讲)
- 第七讲(附小文件)
- 大话数据结构 第七章 图 (读书笔记)
- 数据结构 第七章 图
- 第七讲
- 第七讲
- 第七讲
- 第七讲
- 第七讲
- 陈越《数据结构》第三讲 树(上)
- 陈越《数据结构》第五讲 树(下)
- Machine Learning第七讲[支持向量机] --(一)最大间隔分类
- 数据结构——第四讲、树(中)(1)
- 从傅立叶变换到Gabor滤波器
- 第一次访问本机上的spring-boot报错:java.lang.NumberFormatException: For input string: "index"
- html 返回到上一个页面
- 人工智能十大发展方向
- 老铁,邀请你来免费学习人工智能!!!
- 陈越《数据结构》第七讲 图(中)一
- Spring Framework# @Configurable
- JS监听手机端浏览器的后退按钮的事件方法
- CentOS 7 开放3306端口访问
- leetcode: 41. First Missing Positive
- 【第六届蓝桥杯】加法变乘法
- Qt之pro配置详解
- 用 Linux、Python 和树莓派酿制啤酒
- 技术博客集锦(持续更新)