1064 완전한 이진 검색 트리 (30 分)
이진 검색 트리 (BST)는 재귀 적으로 다음과 같은 속성이 있습니다 이진 트리로 정의된다 :
- 노드의 왼쪽 하위 트리 노드의 키보다 작은 키 노드 만 포함되어 있습니다.
- 노드의 오른쪽 서브 트리보다 크거나 노드의 키와 동일한 키 노드 만 포함되어 있습니다.
- 모두 왼쪽과 오른쪽 서브 트리도 이진 검색 나무이어야합니다.
완전한 이진 트리 (CBT)를 완전히 왼쪽에서 오른쪽으로 채워 바닥 수준의 가능한 예외로 가득 나무입니다.
이제 별개의 음이 아닌 정수 키의 순서를 주어진 고유 한 BST는이 나무가 또한 CBT해야한다는 필요한 경우 구성 할 수있다. 당신은 출력이 BST의 레벨 순서 탐색 순서를 생각하고 있습니다.
입력 사양 :
각 입력 파일은 하나의 테스트 케이스가 포함되어 있습니다. 각 경우에있어서, 첫 번째 라인은 양의 정수 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은 접합점의 개수
순서대로 배열 노드들에서 얻어진 1. 먼저 입력 N 정렬 값
2. 라운딩 로그 그래피 (플로어 () CEIL은 올림 내림) (N + 1)의 최종 층의 높이 (h)의 예를 제공하기 위해 아래로 제거는 : N = 노드 (7)의 높이가 3 (때문에 단지 루트 노드의 값은 마지막 로그 N + 1 개 계층 키를 제거하는 데 필요한)
3. 노드의 개수가 최종 층을 얻었다 : N - (POW (2, H) - 1) (단 좌측 노드가 될 수있다, 우측 노드가)
샘플의 시험 배치 순서 4. 1 : 우리는 좌측 노드 NUM의 수를 알고 0123456789 긴 (의해 좌측 (가장 좌측 노드 선주문) NUM + 결정될 수있다 다음 루트 노드 후) 왼쪽 하위 트리 오른쪽 서브 트리, 편리한 루트 인덱스 레코드 인덱스 시퀀스 출력의 세트에 뿌리를 찾을 수 재귀 적으로 계속
그래서 TEMP2 = (POW (2 시간) - 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;
}