1064年の完全なバイナリ検索ツリー(30分)
バイナリ検索ツリー(BST)を再帰的に以下の特性を有するバイナリツリーのように定義されます。
- ノードの左部分木は、ノードのキーより小さいキーを持つノードのみが含まれています。
- ノードの右サブツリーを超えるまたはノードのキーと同じキーを持つ唯一のノードを含みます。
- 左と右のサブツリーどちらも二分探索木でなければなりません。
完全2分木(CBT)は、完全に左から右に充填されているボトムレベルの可能な例外を除いて、充填されている木です。
今、明確な非負整数キーのシーケンスを与えられた、ユニークなBSTは、木もCBTでなければならないことを要求される場合に構成することができます。あなたがこのBSTの出力レベル順トラバーサル順序になっています。
入力仕様:
各入力ファイルには、1つのテストケースが含まれています。各場合について、最初の行は、正の整数N(≤1000)を含みます。次いで、N個の異なる非負の整数キーは次の行に示されています。行のすべての数字は、スペースで区切り、2000よりも大きくないされています。
出力仕様:
各テストケースのために、一列に対応する完全なバイナリ検索ツリーのレベル順トラバーサル順序を印刷します。行のすべての数字は、スペースで区切る必要があり、ラインの末尾に余分なスペースがあってはなりません。
サンプル入力:
10
1 2 3 4 5 6 7 8 9 0
サンプル出力:
6 3 8 1 5 7 9 0 2 4
参考ギャングブログ: https://blog.csdn.net/richenyunqi/article/details/78868563
このトピックやアイデア
方法1:バイナリツリー検索の完全な自然を使用
Nは、接合点の数であります
まず、入力Nの順序で配置されたノードで得られたソート値
2.最終的な層の高さhなどを与えるまで除去されるログ(N + 1)によって(床()はCEILは切り上げられ、切り捨て)丸め:ため(N =ノード7の高さは3であります唯一のルートノードの値は、最後のログのn + 1層の高さを除去する必要があります)
3.ノードの数は、最終的な層を得るために:N - (POW(2、H) - 1);(だけ左ノードが存在してもよいし、右のノードが存在します)
試料中の試験配列順序4. 1:我々は左ノードNUMの数を知っている0123456789長い;(によって左の(最も左のノードプレオーダー) NUM +を決定することができますその後、ルートノードの後に)、左サブツリー、右部分木、便利なルートインデックスレコードインデックスシーケンス出力のセットにルートを見つける再帰的に続けます
そうTEMP2 =(POW(2、H) - 1)/ 2
5.ノードの左の部分木のキー番号を決定する方法:この場合、ノードの最大数は、最後の層は、左サブツリーに格納することができるTEMP2得られた(格納可能な最大容量の後半一つの)分(TEMP2、Nによって - そして左に総和ノード従って数: - (POW(2、H)1))は、最後の層要素の左サブツリーを与えるためには、このケースに収納することができ、TEMP2 -1左の部分木の最後の層の数を除去することができます:合計= TEMP2 - 1 +分(TEMP2、N - (POW(2、H) - 1))
特定のコード
:
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
int n;
vector<int> in,level;
void levelOrder(int start, int end, int index){
if(start > end) return;
int sum = end - start + 1;
int height = (int)floor(log((sum) + 1) / log(2)); //还没强转 log在cmath库中
int temp1 = sum - (int)(pow(2, height) - 1); //最后一层的结点数量
int temp2 = pow(2, height) / 2; //最后一层能够容纳的最大结点数量的一半
temp1 = min(temp1, temp2); //取最小是因为temp1可能包含右结点,现在只需要算出左结点
temp1 = start + temp1 + temp2 - 1; //此时左子树结点总数为(temp1 + temp2 - 1) 同时加上start(left)就是中序遍历中根结点的下标
level[index] = in[temp1];
levelOrder(start, temp1 - 1, 2 * index + 1);
levelOrder(temp1 + 1, end, 2 * index + 2);
}
int main(){
scanf("%d", &n);
in.resize(n); //在全局遍历中 用(n)也不能scanf输入 这里注意 只有用resize容器具有具体长度时 才能用scanf赋值
level.resize(n);
for(int i = 0; i < n; i++){
scanf("%d", &in[i]);
}
sort(in.begin(), in.end());
levelOrder(0, n-1, 0);
for(auto i = 0; i < n; i++){
if(i != 0) printf(" ");
printf("%d", level[i]);
}
return 0;
}
方法2:
一つの方法は、順次各によって発見ルートアレイレベルに各ノード点の添え字インデックスのノード、
より便利な方法は、アレイ内の各要素は、高さによって決定される各ルート先行予約番号を検索するために必要なレベルに追加されないの直接シーケンスの前順走査することによる、左ノードが見つかりました。
特定のコード:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int n,position=0;
vector<int> level, in;
void levelOrder(int index){
if(index > n-1) return; //注意这里是n-1 因为根节点的下标是0 那么最后一个结点的下标为n-1
levelOrder(index * 2 + 1); // 完全二叉搜索树中中序遍历中 第一个结点会是最左边的结点
level[index] = in[position++];
levelOrder(index * 2 + 2);
}
int main(){
scanf("%d", &n);
level.resize(n);in.resize(n);
for(int i = 0; i < n; i++){
scanf("%d", &in[i]);
}
sort(in.begin(),in.end());
levelOrder(0);
for(int i = 0; i < n; i++){
if(i != 0) printf(" ");
printf("%d", level[i]);
}
return 0;
}