从PAT甲级1064题说开去
来源:互联网 发布:php 常量定义 使用 编辑:程序博客网 时间:2024/06/16 05:05
原题链接:https://www.patest.cn/contests/pat-a-practise/1064
这题的意思是,给定一系列树,要用它构造一棵完全二叉树,这棵完全二叉树满足二叉查找树的性质。
在二叉树的遍历中提到了完全二叉树的概念,它是一棵只有最后一层不满,其他所有层都填满的树,最后一层从左向右依次填满。在二叉树的恢复中提到了二叉查找树的性质,它的左子树上的节点均小于它,右子树的节点都大于等于它,左子树右子树都是二叉查找树。
这样这题的思路就很清晰了:既然这棵树是完全二叉树,那这棵树的形状是固定下来的,再把排序好的数字往里填就可以了。
我利用了二叉树在每层上节点个数的性质,迭代地找到每一棵(子)树的根节点,建立完二叉树以后再层序遍历。
#include<iostream>#include<algorithm>#include<queue>using namespace std;int listof2[11] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 };struct tree_node{ int data = 0; tree_node* left_child = NULL; tree_node* right_child = NULL;};void find_insert_node(tree_node* &this_node, int node_num, int *data_formal){ if (node_num == 0) return; if (node_num == 1) { this_node = new tree_node; this_node->data = *data_formal; return; } if (node_num == 2) { this_node = new tree_node; this_node->data = *(data_formal + 1); this_node->left_child = new tree_node; this_node->left_child->data = *data_formal; return; } if (node_num == 3) { this_node = new tree_node; this_node->data = *(data_formal + 1); this_node->left_child = new tree_node; this_node->left_child->data = *data_formal; this_node->right_child = new tree_node; this_node->right_child->data = *(data_formal + 2); return; } int level; for (level = 0; level < 11; ++level) { if (listof2[level]-1 >= node_num) break; } if (listof2[level] * 3 / 4 - 1 >= node_num) { this_node = new tree_node; this_node->data = *(data_formal + node_num - listof2[level] / 4); find_insert_node(this_node->left_child, node_num - listof2[level] / 4, data_formal); find_insert_node(this_node->right_child, listof2[level] / 4 - 1, data_formal + node_num - listof2[level] / 4 + 1); } else { this_node = new tree_node; this_node->data = *(data_formal + listof2[level] / 2 - 1); find_insert_node(this_node->left_child, listof2[level] / 2 - 1, data_formal); find_insert_node(this_node->right_child, node_num - listof2[level] / 2, data_formal + listof2[level] / 2); }}queue<int> data_save;queue<tree_node*> temp_node;void level_order(){ if (temp_node.empty()) return; tree_node* this_node = temp_node.front(); data_save.push(this_node->data); temp_node.pop(); if (this_node->left_child) temp_node.push(this_node->left_child); if (this_node->right_child) temp_node.push(this_node->right_child); level_order();}int main(){ int num = 10; cin >> num; int data_formal[1000] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; for (int i = 0; i < num; ++i) cin >> data_formal[i]; sort(data_formal, data_formal + num); tree_node* root_node = NULL; find_insert_node(root_node, num, data_formal); temp_node.push(root_node); level_order(); for (int i = 0; i < num; ++i) { cout << data_save.front(); data_save.pop(); if (i != num - 1) cout << " "; } getchar(); getchar(); return 0;}
这个代码可以AC,但是稍有不慎就会出错,很麻烦。
这个大神的解法很美,分析以后发现写出这样的代码需要深厚的数学和编程功底。
#include <cstdio> #include <cstdlib> const int maxx = 1005; int node[maxx]; int tree[maxx]; int pos,n; int cmp(const void *a,const void *b){ int *pa = (int *)a; int *pb = (int *)b; return *pa-*pb; } //用于排序 void build(int root){ if(root>n)return; int lson = root<<1,rson = (root<<1)+1; build(lson); tree[root] = node[pos++]; build(rson); } void print(int *a,int n){ int i; for(i=0;i<n;++i){ printf("%d ",a[i]); } printf("\n"); } //调试代码 int main() { int i; scanf("%d",&n); for(i=0;i<n;++i){ scanf("%d",&node[i]); } qsort(node,n,sizeof(int),cmp); // print(node,n); pos = 0; build(1); printf("%d",tree[1]); for(i=2;i<=n;++i){ printf(" %d",tree[i]); } printf("\n"); return 0; }
仔细分析代码,事实上他的代码将构建二叉树和层序排列二叉树在短短6行内完成了
void build(int root){ //第一次调用时:root=1,pos指向已经升序排列的数组的第一个元素 if(root>n)return; int lson = root<<1,rson = (root<<1)+1; //用左移乘以2 build(lson); tree[root] = node[pos++]; build(rson); }
这篇文章提到了完全二叉树的五个基本性质,其中之一是:
如果有一颗有n个节点的完全二叉树的节点按层次序编号,对任一层的节点i(1<=i<=n)有
1)如果i=1,则节点是二叉树的根,无双亲,如果i>1,则其双亲节点为[i/2],向下取整
2)如果2i>n那么节点i没有左孩子,否则其左孩子为2i
3)如果2i+1>n那么节点没有右孩子,否则右孩子为2i+1
通过这个性质,我们可以定位当前处理的节点在数组中应该储存的位置。
按照中序二叉树的遍历顺序,它会从小到大依次遍历二叉查找树的节点。
知道了这两个信息,我们就可以往数组里一个一个填。
即使看懂了他的代码,我大概也无法短时间内写出这么美的代码吧。
- 从PAT甲级1064题说开去
- 从PAT甲级1047题说开去
- 从"文人相轻"说开去...
- 从“盗版”说开去
- 从PDF说开去
- 从时间说开去
- 从《加速VB》说开去
- 从一个故事说开去
- 从second life说开去
- 从printf说开去(一)
- 从printf说开去(二)
- 从printf说开去(三)
- 从printf说开去(四)
- 从printf说开去(五)
- 从DUMP函数说开去
- [Loader] 从startLoading()说开去..
- 从DUMP函数说开去
- 从软件开发说开去
- PPTP配置VPN服务器
- 处理器体系结构(《深入理解计算机系统》)
- 售货员的难题
- Linux自学笔记(十)常用命令之rpm相关命令
- Java面向对象编程的三大特性
- 从PAT甲级1064题说开去
- 蓝桥杯 水题 翻硬币
- Android stuido 中的keystore
- Java递归求解汉诺塔问题
- Oracle之DBMS_RANDOM 包用法详解
- POJ 3340 Barbara Bennett's Wild Numbers 可能会
- linux c之解决使用socket函数返回为0的问题
- 考研英语
- Spring MVC拦截器详解