此次咱們接着來講樹,上次說了樹的基本性質和遍歷一顆樹的4種方式,此次將會說到幾種很「有用」的二叉樹node
對一顆二叉樹,該如何實現它的動態查找(會有新元素的添加,和對當前樹包含元素的刪除),前面咱們已經學過了咱們二分查找,很天然的若是咱們再構建一棵樹時,若是當前節點的左子樹都比他小,右子樹都比他大,對這樣的樹,咱們叫作二叉搜索樹。根據這樣的性質,咱們能夠很天然的得出,二叉搜索樹最小的節點它的最左端的節點,二叉搜索樹最大的節點它的最右端的節點。數組
咱們知道對於一棵二叉搜索樹,他任何節點的左子樹都比他小,右子樹都比他大,天然的一種二分查找,從根結點開始遍歷,若是當前節點比須要查找的值大從他的右子樹,比須要查找的值小從他的左子樹,相等則返回。若是直到指向爲空都沒法找到,說明該節點並不在樹上,下面是代碼實現。less
//find max value Position FindMax(BinTree BST) { if (!BST) { return NULL; } while (BST->Right) { BST = BST->Right; } return BST; } //find min value Position FindMin(BinTree BST) { if (!BST) { return NULL; } while (BST->Left) { BST = BST->Left; } return BST; } //find in value Position Find(BinTree BST, ElementType X) { //the tree is empty ,return NULL; while (BST) { //the X is big than now position's value, may be in the right or doesn't has. if (X > BST->Data) { BST = BST->Right; } else if (X < BST->Data) { BST = BST->Left; } else { return BST; } } return NULL; }
同查找一個值同樣,對於二叉搜索樹的插入,先從根結點開始遍歷,若是小於它就插入它的左子樹,大於它就插入它的右子樹。直到咱們找到了位置,再申請一個節點將它接上去。函數
//insert BinTree Insert(BinTree BST, ElementType X) { //if the tree is empty,creat a node and return if (!BST) { BST = malloc(sizeof(struct TNode)); BST->Data = X; BST->Left = NULL; BST->Right = NULL; } else { //the X is big than now position, insert X in its right tree if (X > BST->Data) { BST->Right = Insert(BST->Right, X); } //the X is small than now position, insert X in its left tree else if (X < BST->Data) { BST->Left = Insert(BST->Left, X); } //when the X already in the tree, do nothing else { } } return BST; }
二叉樹最多有兩個節點,在刪除時咱們可能遇到幾種狀況,分別是該節點沒有子節點(葉子節點),有一個子節點,有兩個子節點。
若是沒有子節點,咱們直接釋放掉該節點,返回一個NULL接上去。若是隻有一個子節點,咱們只須要釋放該節點,並把他的那個子節點接上去便可。有兩個子節點時,問題變得麻煩起來,有一個策略將是,將問題轉化爲刪除一個葉節點,或刪除一個只有一個兒子的節點。
經過二叉搜索數的性質咱們知道,一顆樹的最小值,位於他的最左端,最大值位於它的最右端,咱們能夠找到該節點右子樹的最小值,賦值給該節點,同時刪除掉它(由於二叉搜索樹的性質,它只多是葉節點,或者只有一個兒子,並且那樣作不會破壞二叉搜索樹的一個節點左子樹都比他小,右子樹都比他大的性質),找該節點左子樹的最大值同理。測試
//delete BinTree Delete(BinTree BST, ElementType X) { if (!BST) { printf("NOT Found\n"); } else { //the X is big than now position, delete X in its right tree if (X > BST->Data) { BST->Right = Delete(BST->Right, X); } //the X is small than now position, delete X in its left tree else if (X < BST->Data) { BST->Left = Delete(BST->Left, X); } //find the X positon else { //has two sub tree if (BST->Left && BST->Right) { BinTree temp = FindMax(BST->Left); BST->Data = temp->Data; temp->Data = X; Delete(BST->Left, X); } //has one or no sub tree else { BinTree temp = BST; //don't has left sub tree if (!BST->Left) { BST = BST->Right; } //don't has right sub tree else if (!BST->Right) { BST = BST->Left; } free(temp); } } } return BST; }
前面我面討論了二叉搜索樹,如今,想象一下,若是咱們按照升序序列將節點(1-10)插入樹中,不難發現,這個樹成了顆單邊樹這樣的樹有着和鏈表同樣的查找效率,確定是不但願發生這樣的事情的,這裏引入一個叫平衡二叉樹的樹(AVL),那麼這種樹有什麼特色呢?
平衡二叉樹由二叉搜索樹而來,一樣的,也是必須知足BST的性質,並且,這顆樹必須知足,全部節點的左右子樹高度差BF(T)=\(h_l\)-\(h_r\)不大於1.
考慮一下,一個n層高的平衡二叉樹最小須要幾個節點?
答案是\(a_n\)=\(1+a_(n-1)+a_(n-2)\)
對於一層高的平衡二叉樹,須要一個節點,兩層高的須要兩個節點,三層高的則須要一個節點加上它的左子樹(兩層的平衡二叉樹)和他的右子樹一層的平衡二叉樹。整個是一個遞歸的過程ui
爲了保證平衡二叉樹的性質,咱們再插入節點或者刪除節點時,使該樹不平衡時,又應該如何調整它使它平衡呢?根據上面平衡二叉樹是一個遞歸的生成過程,咱們能夠知道,對於插入或者刪除,只須要修正被破壞平衡的節點爲根節點構成的樹,即修正整棵樹的平衡。this
第一種狀況,破壞了平衡的節點,位於被破壞平衡節點的右子樹的右子樹,此時將被破壞平衡節點的右兒子提起來,本身作右兒子的左兒子,將右兒子的左兒子作本身的右兒子。(RR旋轉)spa
第二種狀況,破壞了平衡的節點,位於被破壞平衡節點的左子樹的左子樹,根據對稱性咱們很容易想到,此時將被破壞平衡節點的左兒子提起來,本身作左兒子的右兒子,將左兒子的右兒子作本身的左兒子。(LL旋轉)指針
第三種狀況,破壞了平衡的節點,位於被破壞平衡節點的左子樹的右子樹,此時將破壞平衡節點的所在樹的根節點提出來作新的根,並令該根的左兒子爲原樹根的左兒子,右兒子爲原樹根節點。而且把破壞平衡節點的所在樹的根節點的左右子樹,分別接在當前根節點左兒子的右邊和右兒子的左邊。(LR旋轉)rest
第四種狀況,相似於第3種狀況的對稱,破壞了平衡的節點,位於被破壞平衡節點的右子樹的左子樹,只需對稱着像第三種狀況那樣作。(RL旋轉)
(圖片來源https://www.icourse163.org/learn/ZJU-93001?tid=1461682474#/learn/content?type=detail&id=1238255569&cid=1258682934)
給定一個插入序列就能夠惟一肯定一棵二叉搜索樹。然而,一棵給定的二叉搜索樹卻能夠由多種不一樣的插入序列獲得。例如分別按照序列{2, 1, 3}和{2, 3, 1}插入初始爲空的二叉搜索樹,都獲得同樣的結果。因而對於輸入的各類插入序列,你須要判斷它們是否能生成同樣的二叉搜索樹。
輸入格式:
輸入包含若干組測試數據。每組數據的第1行給出兩個正整數N (≤10)和L,分別是每一個序列插入元素的個數和須要檢查的序列個數。第2行給出N個以空格分隔的正整數,做爲初始插入序列。最後L行,每行給出N個插入的元素,屬於L個須要檢查的序列。
簡單起見,咱們保證每一個插入序列都是1到N的一個排列。當讀到N爲0時,標誌輸入結束,這組數據不要處理。
輸出格式:
對每一組須要檢查的序列,若是其生成的二叉搜索樹跟對應的初始序列生成的同樣,輸出「Yes」,不然輸出「No」。
輸入樣例:
4 2
3 1 4 2
3 4 1 2
3 2 4 1
2 1
2 1
1 2
0
輸出樣例:
Yes
No
No
解法:模擬法,將默認樹讀入保存,每次讀入生成一個新樹,再遞歸去判斷每一個節點位置是否相同,不一樣返回false,相同返回判斷左右兩個子樹是否相同的合取運算,若是傳入的兩個樹都空,返回true,其中一個不空返回false,都不空再去判斷
代碼實現:
#include<stdio.h> #include<stdlib.h> #include<stdbool.h> typedef struct TreeNode* BinTree; #define ElementType int struct TreeNode { ElementType Data; BinTree Left; BinTree Right; }; //insert BinTree insert(ElementType X, BinTree BST) { //if the tree is empty,creat a node and return if (!BST) { BST = (BinTree)malloc(sizeof(struct TreeNode)); BST->Data = X; BST->Left = NULL; BST->Right = NULL; } else { //the X is big than now position, insert X in its right tree if (X > BST->Data) { BST->Right = insert(X, BST->Right); } //the X is small than now position, insert X in its left tree else if (X < BST->Data) { BST->Left = insert(X, BST->Left); } //when the X already in the tree, do nothing else { } } return BST; } bool check(BinTree T1, BinTree T2) { if (T1==NULL && T2==NULL) { return true; } if(T1->Data==T2->Data){ return check(T1->Left, T2->Left)&&check(T1->Right, T2->Right); } return false; } int main() { int n, l; while (scanf("%d", &n)) { if (n == 0) { break; } scanf("%d", &l); BinTree OT = NULL; for (int i = 0; i < n; i++) { int temp; scanf("%d", &temp); OT = insert(temp, OT); } for (int j = 0; j < l; j++) { BinTree TestTree = NULL; for (int i = 0; i < n; i++) { int temp; scanf("%d", &temp); TestTree = insert(temp, TestTree); } if (!check(OT, TestTree)) { printf("No\n"); } else { printf("Yes\n"); } } } }
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.
Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤20) which is the total number of keys to be inserted. Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print the root of the resulting AVL tree in one line.
Sample Input 1:
5
88 70 61 96 120
Sample Input 1:
70
解析:題目的意思是,讓你構建一顆2叉平衡樹,給定你插入序列,讓你輸出他的根節點,emm....那就模擬作一顆AVL(思路課程已經說了,就是把代碼轉化成程序的過程)
代碼:
#include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; typedef struct TreeNode* BinTree; #define ElementType int struct TreeNode { ElementType Data; BinTree Left; BinTree Right; int Height; }; int getHeight(BinTree T) { if (T->Left == NULL && T->Right == NULL) { return 1; } else if (T->Left != NULL && T->Right == NULL) { return T->Left->Height+1; } else if (T->Left == NULL && T->Right != NULL) { return T->Right->Height + 1; } else { return max(T->Left->Height, T->Right->Height)+1; } } BinTree RR(BinTree T) { BinTree right = T->Right; T->Right = right->Left; right->Left = T; right->Height = getHeight(right); T->Height = getHeight(T); return right; } BinTree LL(BinTree T) { BinTree left = T->Left; T->Left = left->Right; left->Right = T; left->Height = getHeight(left); T->Height = getHeight(T); return left; } BinTree LR(BinTree T) { T->Left = RR(T->Left); return LL(T); } BinTree RL(BinTree T) { T->Right = LL(T->Right); return RR(T); } //insert BinTree Insert(BinTree BST, ElementType X) { //if the tree is empty,creat a node and return if (!BST) { BST = (BinTree)malloc(sizeof(struct TreeNode)); BST->Data = X; BST->Left = NULL; BST->Right = NULL; BST->Height = 0; } else { //the X is big than now position, insert X in its right tree if (X > BST->Data) { BST->Right = Insert(BST->Right, X); int h1, h2; if (BST->Left == NULL) { h1 = 0; } else { h1 = BST->Left->Height; } if (BST->Right == NULL) { h2 = 0; } else { h2 = BST->Right->Height; } //the tree is not avl if (abs(h1-h2)==2) { //LL if (X < BST->Right->Data) { BST = RL(BST); } //LR else { BST = RR(BST); } } } //the X is small than now position, insert X in its left tree else if (X < BST->Data) { BST->Left = Insert(BST->Left, X); int h1, h2; if (BST->Left == NULL) { h1 = 0; } else { h1 = BST->Left->Height; } if (BST->Right == NULL) { h2 = 0; } else { h2 = BST->Right->Height; } if (abs(h1-h2) == 2) { //RR if (X > BST->Left->Data) { BST = LR(BST); } //RL else { BST = LL(BST); } } } //when the X already in the tree, do nothing else { } } BST->Height = getHeight(BST); return BST; } int main(void) { int n; scanf("%d", &n); BinTree BST = NULL; for (int i = 0; i < n; i++) { int temp; scanf("%d", &temp); BST = Insert(BST, temp); } printf("%d\n", BST->Data); return 0; }
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
題解:
題目的意思是給你N個數字,讓你把它排成徹底二叉搜索樹(同時具備二差搜索樹的性質和徹底二叉樹的性質),輸出這棵樹的程序遍歷。仔細想一下其實根本不用構建一棵樹,由於徹底二叉樹固定了節點的位置 ,這棵樹只可能有一種形狀,咱們只須要將這N個數字排好序 ,遞歸的把它存進樹組中,數組一位置爲開始節點,他的兒子就是他當前位置的二倍和二倍加1。
代碼實現:
#include<cstdio> #include<algorithm> #include<string.h> #include<math.h> #include<stdbool.h> using namespace std; int arr1[1001]; int arr[1001]; int getrootIndex(int Left,int Right) { int p = floor(log10(Right-Left+1)/ log10(2)); int leftnum = min(pow(2,p-1), (Right - Left + 1)-(pow(2, p)-1)); return Left+leftnum+ (pow(2, p-1) - 1); } void specialSort(int Left,int Right,int root) { if (Left>Right) { return; } else if (Left == Right) { arr1[root] = arr[Left]; } else { int p = getrootIndex(Left, Right); arr1[root] = arr[p]; specialSort(Left, p - 1, root * 2); specialSort(p+1, Right, root * 2+1); } } int main() { int n, t; scanf("%d",&n); memset(arr, 10000, sizeof(arr)); memset(arr1, 10000, sizeof(arr1)); for (int i = 0; i < n; i++) { scanf("%d", &t); arr[i] = t; } sort(arr, arr + n); specialSort(0, n - 1, 1); bool isf = true; for (int i = 1; i <= n; i++) { if (isf) { printf("%d",arr1[i]); isf = false; } else { printf(" %d", arr1[i]); } } return 0; }
本題要求實現給定二叉搜索樹的5種經常使用操做。
函數接口定義:
BinTree Insert( BinTree BST, ElementType X ); BinTree Delete( BinTree BST, ElementType X ); Position Find( BinTree BST, ElementType X ); Position FindMin( BinTree BST ); Position FindMax( BinTree BST );
其中BinTree結構定義以下:
typedef struct TNode *Position; typedef Position BinTree; struct TNode{ ElementType Data; BinTree Left; BinTree Right; };
裁判測試程序樣例:
#include <stdio.h> #include <stdlib.h> typedef int ElementType; typedef struct TNode *Position; typedef Position BinTree; struct TNode{ ElementType Data; BinTree Left; BinTree Right; }; void PreorderTraversal( BinTree BT ); /* 先序遍歷,由裁判實現,細節不表 */ void InorderTraversal( BinTree BT ); /* 中序遍歷,由裁判實現,細節不表 */ BinTree Insert( BinTree BST, ElementType X ); BinTree Delete( BinTree BST, ElementType X ); Position Find( BinTree BST, ElementType X ); Position FindMin( BinTree BST ); Position FindMax( BinTree BST ); int main() { BinTree BST, MinP, MaxP, Tmp; ElementType X; int N, i; BST = NULL; scanf("%d", &N); for ( i=0; i<N; i++ ) { scanf("%d", &X); BST = Insert(BST, X); } printf("Preorder:"); PreorderTraversal(BST); printf("\n"); MinP = FindMin(BST); MaxP = FindMax(BST); scanf("%d", &N); for( i=0; i<N; i++ ) { scanf("%d", &X); Tmp = Find(BST, X); if (Tmp == NULL) printf("%d is not found\n", X); else { printf("%d is found\n", Tmp->Data); if (Tmp==MinP) printf("%d is the smallest key\n", Tmp->Data); if (Tmp==MaxP) printf("%d is the largest key\n", Tmp->Data); } } scanf("%d", &N); for( i=0; i<N; i++ ) { scanf("%d", &X); BST = Delete(BST, X); } printf("Inorder:"); InorderTraversal(BST); printf("\n"); return 0; } /* 你的代碼將被嵌在這裏 */
輸入樣例:
10
5 8 6 2 4 1 0 10 9 7
5
6 3 10 0 5
5
5 7 0 10 3
輸出樣例
Preorder: 5 2 1 0 4 8 6 7 10 9
6 is found
3 is not found
10 is found
10 is the largest key
0 is found
0 is the smallest key
5 is found
Not Found
Inorder: 1 2 4 6 8 9
解析:實現的函數即爲本章第1節部分的內容,跟着思路寫就好
代碼:
//find max value Position FindMax(BinTree BST) { if (!BST) { return NULL; } while (BST->Right) { BST = BST->Right; } return BST; } //find min value Position FindMin(BinTree BST) { if (!BST) { return NULL; } while (BST->Left) { BST = BST->Left; } return BST; } //find in value Position Find(BinTree BST, ElementType X) { //the tree is empty ,return NULL; while (BST) { //the X is big than now position's value, may be in the right or doesn't has. if (X > BST->Data) { BST = BST->Right; } else if (X < BST->Data) { BST = BST->Left; } else { return BST; } } return NULL; } //insert BinTree Insert(BinTree BST, ElementType X) { //if the tree is empty,creat a node and return if (!BST) { BST = malloc(sizeof(struct TNode)); BST->Data = X; BST->Left = NULL; BST->Right = NULL; } else { //the X is big than now position, insert X in its right tree if (X > BST->Data) { BST->Right = Insert(BST->Right, X); } //the X is small than now position, insert X in its left tree else if (X < BST->Data) { BST->Left = Insert(BST->Left, X); } //when the X already in the tree, do nothing else { } } return BST; } //delete BinTree Delete(BinTree BST, ElementType X) { if (!BST) { printf("Not Found\n"); } else { //the X is big than now position, delete X in its right tree if (X > BST->Data) { BST->Right = Delete(BST->Right, X); } //the X is small than now position, delete X in its left tree else if (X < BST->Data) { BST->Left = Delete(BST->Left, X); } //find the X positon else { //has two sub tree if (BST->Left && BST->Right) { BinTree temp = FindMax(BST->Left); BST->Data = temp->Data; temp->Data = X; Delete(BST->Left, X); } //has one or no sub tree else { BinTree temp = BST; //don't has left sub tree if (!BST->Left) { BST = BST->Right; } //don't has right sub tree else if (!BST->Right) { BST = BST->Left; } free(temp); } } } return BST; }