以下圖所示:15爲樹的根節點,10爲15的左節點,20爲15的右節點,下面的節點如此類推。數組
每一個父節點都有兩個子節點(子節點可能爲空),左子節點比父節點小,右子節點比父節點大。dom
每一個節點應該含有兩個子節點,一個能夠進行比較的key(本文使用的是int)。節點能夠根據需求來含有其它附屬內容,本文爲了方便測試,節點含有一個String和記錄該節點下面共有多少個節點(包括本身)的Count。ide
節點實現:測試
UCLASS() class ALGORITHM_API ATreeNode : public AActor { GENERATED_BODY() public: // Sets default values for this actor's properties ATreeNode(); // Called every frame virtual void Tick(float DeltaTime) override; //設值 FORCEINLINE void SetValue(int Newkey, FString NewValue) { Key = Newkey; Value = NewValue; } FORCEINLINE ATreeNode* Get() { return this; } //獲取或修改私有變量 FORCEINLINE int GetKey() { return Key; } FORCEINLINE void SetKey(int NewKey) { Key = NewKey; } FORCEINLINE int GetCount() { return Count; } FORCEINLINE void SetCount(int NewCount) { Count = NewCount; } FORCEINLINE FString GetValue() { return Value; } FORCEINLINE void SetValue(FString NewValue) { Value = NewValue; } FORCEINLINE ATreeNode* GetNode(bool Left) { if (Left) return LeftNode; return RightNode; } FORCEINLINE void SetNode(bool Left, ATreeNode* NewNode) { if (Left) LeftNode = NewNode; else { RightNode = NewNode; } } protected: // Called when the game starts or when spawned virtual void BeginPlay() override; private: int Key; FString Value; //左右節點 ATreeNode* LeftNode; ATreeNode* RightNode; //計算此節點下面共用多少個節點(包括本身) int Count; };
若是想查找某個數字X,從根節點開始比較。若是X比根節點大,則去與根節點的右節點比較,如此類推,直到找到X(或子節點爲空)爲止。this
例如上圖二叉搜索樹中,若是想找25:spa
從根節點開始比較:25>15。去根節點右邊,與下一個節點(20)比較,結果25>20。接着去右邊,與下一個節點(25)比較,結果25=25,查找成功。3d
代碼實現:指針
FString ABinarySearchTrees::GetValue(int InputKey) { ATreeNode* X = RootNode; while (X != nullptr) { //比較key的大小 int Temp = CompareTo(InputKey, X->GetKey()); //若是輸入的key比X的小,去X的左邊 if (Temp < 0) X = X->GetNode(true); //若是輸入的key比X的大,去X的右邊 else if (Temp > 0) X = X->GetNode(false); //若是相等,說明找到這個key了,輸出Value else return X->GetValue(); } //若是X爲空指針,說明找不到這個key return "NotFind"; }
若是新節點的key在樹中已經存在,則把舊節點覆蓋;若是沒有,則插入。code
與查找相似,設新節點的key爲X,從根節點開始比較。若是X比根節點大,則去與根節點的右節點比較。如此類推,若是找到了某個節點的key與X相同,覆蓋這個節點;若是沒找到,則根據最後一次比較結果,插到最後一次比較的節點的左節點或右節點。orm
實現代碼:
void ABinarySearchTrees::Put(int Newkey) { //每次插入前,都清空路線信息 RouteString = ""; //每次插入新節點都要更新根節點 RootNode = Put(RootNode, Newkey); RootNode->SetValue(": Root"); } ATreeNode* ABinarySearchTrees::Put(ATreeNode* X, int NewKey) { //若是X不存在,創造一個 if (!X) { ATreeNode* NewNode = GetWorld()->SpawnActor<ATreeNode>(ATreeNode::StaticClass()); NewNode->SetValue(NewKey, RouteString); //節點存起來,方便測試 NodeArray.Add(NewNode); //新節點本身算一個節點 NewNode->SetCount(1); return NewNode; } int Temp = CompareTo(NewKey, X->GetKey()); //若是要插入新節點,則新節點的全部父節點都要更新一次 if (Temp < 0) { RouteString.Append(": Left"); X->SetNode(true, Put(X->GetNode(true), NewKey)); } else if (Temp > 0) { RouteString.Append(": Right"); X->SetNode(false, Put(X->GetNode(false), NewKey)); } else { X->SetValue(RouteString); } //更新X節點的Count X->SetCount(1 + Size(X->GetNode(true)) + Size(X->GetNode(false))); return X; }
查找最小值:由於二叉搜索樹中,左節點比父節點小,故最小值確定在樹的左下角。從根節點開始,判斷它的左節點存不存在。若是存在,繼續找這個左節點的左節點,如此類推,直到找到某個節點的左節點不存在時,此節點就是最小值。
查找最大值:由於二叉搜索樹中,右節點比父節點大,故最大值確定在樹的右下角。從根節點開始,判斷它的右節點存不存在。若是存在,繼續找這個右節點的右節點,如此類推,直到找到某個節點的右節點不存在時,此節點就是最大值。
實現代碼:
//尋找最小值 int ABinarySearchTrees::FindMin() { //從根節點開始比較 ATreeNode* X = FindMin(RootNode); if (X) return X->GetKey(); return 0; } //尋找擁有最小值的節點 ATreeNode* ABinarySearchTrees::FindMin(ATreeNode* X) { //當節點存在時 while (X) { //若是右節點存在,繼續循環 if (X->GetNode(true)) { X = X->GetNode(true); } //若是右節點不存在,這個節點就是最小值 else { return X; } } return X; } int ABinarySearchTrees::FindMax() { //從根節點開始比較 ATreeNode* X = FindMax(RootNode); if (X) return X->GetKey(); return 0; } //尋找擁有最大值的節點 ATreeNode* ABinarySearchTrees::FindMax(ATreeNode* X) { //當節點存在時 while (X) { //若是右節點存在,繼續循環 if (X->GetNode(false)) { X = X->GetNode(false); } //若是右節點不存在,這個節點就是最小值 else { return X; } } return X; }
Floor:最接近此key,且小於等於它的節點。
Ceiling:最接近此key,且大於等於它的節點。
尋找Floor:從下面的例子中介紹思路
假設給定key爲X,現有搜索樹以下圖
假設X=13:
1.從根節點開始比較,X比19小,去19節點的左邊。
2.X>10,但因爲最接近X的節點可能在10的右節點下面,故還需去10的右邊繼續找。
3.X<14, 去14的左邊。
4.X>12,且12沒子節點,故12就是X的Floor。
假設X=11:
1.從根節點開始比較,X比19小,去19節點的左邊。
2.X>10,但因爲最接近X的節點可能在10的右節點下面,故還需去10的右邊繼續找。
3.X<14, 去14的左邊。
4.X<12,且12沒左子節點,故10的右節點下面沒有比X小的節點,10就是X的Floor。
思路:
1.X與根節點比較,若是X小,去根節點的左節點,繼續比較,直到找到一個比X小的節點A爲止。
2.去A節點的右節點找比X小的節點。若是找不到,A就是要找的節點;若是找到了,令此節點爲B,判斷B節點是否有右節點,若是有,重複步驟2;若是沒有,B節點就是要找的節點。
尋找Ceiling的過程與Floor相似,在此不累贅。
實現代碼:
//給定一個數字,尋找最接近它的key(比它小) int ABinarySearchTrees::FindFloor(int InputKey) { //從根節點開始比較 ATreeNode* X = FindFloor(RootNode,InputKey); if (X) return X->GetKey(); return 0; } ATreeNode* ABinarySearchTrees::FindFloor(ATreeNode* X, int InputKey) { //若是X節點不存在,就別繼續下去了 if (!X) return nullptr; int Temp = CompareTo(InputKey, X->GetKey()); //若是存在節點的key與輸入值相等,則這個節點就是最接近它了 if (Temp == 0) return X; //若是節點的key比較大,則去找它的左節點,直到找到小於等於輸入值的節點爲止 if (Temp < 0) return FindFloor(X->GetNode(true), InputKey); //若是節點的key比較小,則要找的節點可能在它的右節點的左端 ATreeNode* T = FindFloor(X->GetNode(false), InputKey); //若是找到了T,則說明找到了,返回T;若是找不到,說明X已是最接近的了,返回X if (T) return T; else return X; } //給定一個數字,尋找最接近它的key(比它大) int ABinarySearchTrees::FindCeiling(int InputKey) { //從根節點開始比較 ATreeNode* X = FindCeiling(RootNode, InputKey); if (X) return X->GetKey(); return 0; } ATreeNode* ABinarySearchTrees::FindCeiling(ATreeNode* X, int InputKey) { //若是X節點不存在,就別繼續下去了 if (!X) return nullptr; int Temp = CompareTo(InputKey, X->GetKey()); //若是存在節點的key與輸入值相等,則這個節點就是最接近它了 if (Temp == 0) return X; //若是節點的key比較小,則去找它的右節點,直到找到大於等於輸入值的節點爲止 if (Temp > 0) return FindCeiling(X->GetNode(false), InputKey); //若是節點的key比較大,則要找的節點可能在它的左節點的左端 ATreeNode* T = FindCeiling(X->GetNode(true), InputKey); //若是找到了T,則說明找到了,返回T;若是找不到,說明X已是最接近的了,返回X if (T) return T; else return X; }
這裏就會用到節點裏的Count了。這個Count記錄了該節點下面共有多少個節點(包括本身)。
從例子介紹思路:
假設給定key爲X,現有搜索樹以下圖
假設X=13,令根節點爲A節點
1.從A節點開始比較,X比19小,去19節點的左邊。
2.X>10,此時10和10左節點如下的全部節點都比X小,由於10的右節點下面可能還有節點比K小,因此還須要繼續找,假設還有Y個節點在下面,則Rank(X)=1+4.Count+Y
3.X<14, 去14的左邊。
4.X>12,且12沒子節點,故Y=12.Count=1,Rank(X)=1+4.Count+Y=1+3+1=5。
思路:
令根節點爲A節點
1. 從A節點開始比較:
若是X<A.key,則若是A的左節點存在,令A的左節點爲A,重複步驟1;若是不存在,返回0;
若是X=A.key,則因爲A的右節點下方都比A大,A的左節點下方都比A小,因此Rank(X)=A的左節點的Count;
若是X>A.key,則Rank(X)=1 + A的左節點的Count + A的右節點下方小於X的節點個數,進入步驟2。
2. 令A的右節點爲A,重複步驟1。
3. 此循環結束後,便獲得Rank(X)。
實現代碼:
//求有多少個數字少於給定數字 int ABinarySearchTrees::Rank(int InputKey) { return Rank(InputKey, RootNode); } int ABinarySearchTrees::Rank(int InputKey, ATreeNode* X) { //若是節點不存在,返回0 if (!X) return 0; int Temp = CompareTo(InputKey, X->GetKey()); //若是給定數字比X的key小,則去X的左邊去找比給定數字小的數字 if (Temp < 0) return Rank(InputKey, X->GetNode(true)); //若是給定數字比X的key大,則X和X的左節點都比給定數字小,把它們算上後,去X的右節點找是否還有比給定數字小的數字 else if (Temp > 0) return 1 + Size(X->GetNode(true)) + Rank(InputKey, X->GetNode(false)); //由於右節點都比X大,而X的Key與給定數字相等,故比給定數字小的數字都在X的左節點裏 else return Size(X->GetNode(true)); }
經過對二叉搜索樹進行中序排列,能夠獲得一個遞增的有序數組。對某個節點進行中序排列就是先排此節點的左節點,再排這個節點,最後排此節點的右節點。
例如對下圖的節點4進行中序排列:2,4,7。
若是要對一個大節點排序,以下圖:
對節點10進行中序排列:須要先對節點4進行中序排列,而後排10,再對節點14進行中序排列
一樣道理,對根節點排序(即整個二叉搜索樹進行中序排列):
對節點19進行中序排列:須要先對節點10進行中序排列,而後排19,再對節點25進行中序排列
實現代碼:
void ABinarySearchTrees::InorderTraversal() { OrderNodeArray.Empty(); Inorder(RootNode); } void ABinarySearchTrees::Inorder(ATreeNode* X) { if (!X) return; //先去加X的左節點 Inorder(X->GetNode(true)); //再加X OrderNodeArray.Add(X->GetKey()); //最後加X的右節點 Inorder(X->GetNode(false)); }
要刪除一個節點,可能會遇到3種狀況:
A. 這個節點沒子節點,此狀況最爲簡單,直接刪除這個節點便可。
B. 這個節點只有一個子節點,把這個子節點和這個節點的父節點相連,而後刪除這個節點
C. 這個節點有兩個子節點,此狀況最爲複雜,稍後討論
舉個例子:
若是要刪除節點2,則就是A狀況,直接刪除便可;
若是要刪除節點4,則就是B狀況,因爲4節點是10節點的左節點,故把節點2放在節點10的左節點處,而後刪除節點4。
若是要刪除節點10,則就是C狀況,首先,咱們須要從節點10下面找一個節點X來代替它,以下圖所示:
能夠看出X確定比4大,比14小。故X只能從14的下面去找。顯然,在此例子中X=12。替代了後,咱們固然須要把14的左節點刪掉,替換效果:
爲了更直觀的討論,咱們不妨將此樹拓展一下:
刪除節點10後:
此時,X確定比4大,比14小,X的候選者有11,12,13。
不能選12,由於12有兩個節點,處理起來過於複雜,且會破壞二叉搜索樹的結構
11能夠選,處理起來最簡單。
不能選13,由於若是X=13,就會破壞了二叉搜索樹的結構,以下圖:
在二叉搜索樹的結構中,父節點應該比它的右節點下面的全部節點都小。而此例子中,13>12>11。
選擇11時,X=11,刪除節點成功,以下圖
所以,回到狀況C:這個節點有兩個子節點,要刪除它的操做是:
1. 今後節點的右節點下面找出最小的節點X。
2. 由於X節點是最小的,因此它的子節點數量確定小於等於1個,把此子節點連到X的父節點上。
3. 而後用X節點替換要刪除的節點。
4. 刪除要刪除的節點。
至於怎麼刪除最小節點,上面已經介紹瞭如何找到最小節點,要刪除它只需在此基礎上進行少許操做。
實現代碼:
//刪除最小的節點 void ABinarySearchTrees::DeleteMin() { RootNode = DeleteMin(RootNode); } ATreeNode* ABinarySearchTrees::DeleteMin(ATreeNode* X) { //若是X的左節點不存在,說明已經找到最小值了,刪除它,返回它的右節點 if (!X->GetNode(true)) { ATreeNode* TempNode = X->GetNode(false); NodeArray.Remove(X); X->Destroy(); return TempNode; } //刪除最小值後,把它的右節點和上一個節點連上 X->SetNode(true, DeleteMin(X->GetNode(true))); //更新節點數 X->SetCount(1 + Size(X->GetNode(true)) + Size(X->GetNode(false))); return X; } void ABinarySearchTrees::Delete(int InputKey) { RootNode = Delete(RootNode, InputKey); } ATreeNode* ABinarySearchTrees::Delete(ATreeNode* X, int InputKey) { if (!X) return nullptr; int Temp = CompareTo(InputKey, X->GetKey()); //尋找要刪除的節點,只要刪了一個節點,它上面的全部節點都要更新一次,因此是SetNode if (Temp < 0) X->SetNode(true, Delete(X->GetNode(true), InputKey)); else if (Temp > 0) X->SetNode(false, Delete(X->GetNode(false), InputKey)); //找到要刪除的節點了 else { //若是要刪除的節點只有一個子節點或沒有,那好辦,只需把那個子節點替代它就好 if (!X->GetNode(false)) { ATreeNode* TempNode = X->GetNode(true); NodeArray.Remove(X); X->Destroy(); return TempNode; } if (!X->GetNode(true)) { ATreeNode* TempNode = X->GetNode(false); NodeArray.Remove(X); X->Destroy(); return TempNode; } //若是要刪除的節點有兩個個子節點,從它的右邊找一個最小的節點來替代它 ATreeNode* T = X; X = FindMin(T->GetNode(false)); X->SetNode(false, DeleteMin(T->GetNode(false))); X->SetNode(true, T->GetNode(true)); NodeArray.Remove(T); T->Destroy(); } //更新節點數 X->SetCount(Size(X->GetNode(true)) + Size(X->GetNode(false)) + 1); return X; }
節點.h: UCLASS() class ALGORITHM_API ATreeNode : public AActor { GENERATED_BODY() public: // Sets default values for this actor's properties ATreeNode(); // Called every frame virtual void Tick(float DeltaTime) override; //設值 FORCEINLINE void SetValue(int Newkey, FString NewValue) { Key = Newkey; Value = NewValue; } FORCEINLINE ATreeNode* Get() { return this; } //獲取或修改私有變量 FORCEINLINE int GetKey() { return Key; } FORCEINLINE void SetKey(int NewKey) { Key = NewKey; } FORCEINLINE int GetCount() { return Count; } FORCEINLINE void SetCount(int NewCount) { Count = NewCount; } FORCEINLINE FString GetValue() { return Value; } FORCEINLINE void SetValue(FString NewValue) { Value = NewValue; } FORCEINLINE ATreeNode* GetNode(bool Left) { if (Left) return LeftNode; return RightNode; } FORCEINLINE void SetNode(bool Left, ATreeNode* NewNode) { if (Left) LeftNode = NewNode; else { RightNode = NewNode; } } protected: // Called when the game starts or when spawned virtual void BeginPlay() override; private: int Key; FString Value; //左右節點 ATreeNode* LeftNode; ATreeNode* RightNode; //計算此節點下面共用多少個節點(包括本身) int Count; };
二叉搜索樹.h: class ATreeNode; UCLASS() class ALGORITHM_API ABinarySearchTrees : public AActor { GENERATED_BODY() public: // Sets default values for this actor's properties ABinarySearchTrees(); // Called every frame virtual void Tick(float DeltaTime) override; //查值 FString GetValue(int InputKey); //某個key是否存在? bool Search(int InputKey); //插入一個節點 void Put(int Newkey); ATreeNode* Put(ATreeNode* X, int NewKey); //提供一個方法讓TreeNode之間進行比較 //若是a大於b,返回1;若是a小於b,返回-1;若是相等,返回0 int CompareTo(int a, int b); //尋找最小值 int FindMin(); //尋找擁有最小值的節點 ATreeNode* FindMin(ATreeNode* X); //尋找最大值 int FindMax(); //尋找擁有最大值的節點 ATreeNode* FindMax(ATreeNode* X); //給定一個數字,尋找最接近它的key(比它小) int FindFloor(int InputKey); ATreeNode* FindFloor(ATreeNode* X, int InputKey); //給定一個數字,尋找最接近它的key(比它大) int FindCeiling(int InputKey); ATreeNode* FindCeiling(ATreeNode* X, int InputKey); //求有多少個數字少於給定數字 int Size(ATreeNode* X); int Rank(int InputKey); int Rank(int InputKey, ATreeNode* X); //中序遍歷 void InorderTraversal(); void Inorder(ATreeNode* X); //刪除最小值 void DeleteMin(); ATreeNode* DeleteMin(ATreeNode* X); //刪除某個節點 void Delete(int InputKey); ATreeNode* Delete(ATreeNode* X, int InputKey); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; public: private: //根節點 ATreeNode* RootNode; //節點數組 TArray<ATreeNode*> NodeArray; //把節點接過的路線記錄下來,方便測試 FString RouteString; //把節點按中序遍歷放進數組 TArray<int> OrderNodeArray; }; 二叉搜索樹.cpp: // Sets default values ABinarySearchTrees::ABinarySearchTrees() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; } // Called when the game starts or when spawned void ABinarySearchTrees::BeginPlay() { Super::BeginPlay(); FRandomStream Stream; Stream.GenerateNewSeed(); //生成節點 for (int i = 0; i < 100; i++) { Put(Stream.RandRange(0, 100)); } Put(40); //測試二叉搜索樹是否正確 for (int i = 0; i < NodeArray.Num(); i++) { UKismetSystemLibrary::PrintString(this, FString::FromInt(NodeArray[i]->GetKey())+ NodeArray[i]->GetValue()+" Count: "+ FString::FromInt(NodeArray[i]->GetCount())); } UKismetSystemLibrary::PrintString(this, FString::FromInt(Rank(49))); //測試搜索和查值功能 if (Search(40)) { UKismetSystemLibrary::PrintString(this, "Find 40: " + GetValue(40)); } //測試尋找最小值、最大值、Floor、Ceiling UKismetSystemLibrary::PrintString(this, "Min: " + FString::FromInt(FindMin()) + " Max: " + FString::FromInt(FindMax())); UKismetSystemLibrary::PrintString(this, "Floor of 50: " + FString::FromInt(FindFloor(50))); UKismetSystemLibrary::PrintString(this, "Ceiling of 50: " + FString::FromInt(FindCeiling(50))); //測試刪除 Delete(40); //測試中序排序 InorderTraversal(); for (int i = 0; i < OrderNodeArray.Num(); i++) { UKismetSystemLibrary::PrintString(this, FString::FromInt(OrderNodeArray[i])); } for (int i = 0; i < NodeArray.Num(); i++) { if (!NodeArray[i]) return; UKismetSystemLibrary::PrintString(this, FString::FromInt(NodeArray[i]->GetKey()) + NodeArray[i]->GetValue() + " Count: " + FString::FromInt(NodeArray[i]->GetCount())); } } // Called every frame void ABinarySearchTrees::Tick(float DeltaTime) { Super::Tick(DeltaTime); } FString ABinarySearchTrees::GetValue(int InputKey) { ATreeNode* X = RootNode; while (X != nullptr) { //比較key的大小 int Temp = CompareTo(InputKey, X->GetKey()); //若是輸入的key比X的小,去X的左邊 if (Temp < 0) X = X->GetNode(true); //若是輸入的key比X的大,去X的右邊 else if (Temp > 0) X = X->GetNode(false); //若是相等,說明找到這個key了,輸出Value else return X->GetValue(); } //若是X爲空指針,說明找不到這個key return "NotFind"; } //某個key是否存在? bool ABinarySearchTrees::Search(int InputKey) { ATreeNode* X = RootNode; while (X != nullptr) { //比較key的大小 int Temp = CompareTo(InputKey, X->GetKey()); //若是輸入的key比X的小,去X的左邊 if (Temp < 0) X = X->GetNode(true); //若是輸入的key比X的大,去X的右邊 else if (Temp > 0) X = X->GetNode(false); //若是相等,說明找到這個key了 else return true; } //若是X爲空指針,說明找不到這個key return false; } void ABinarySearchTrees::Put(int Newkey) { //每次插入前,都清空路線信息 RouteString = ""; //每次插入新節點都要更新根節點 RootNode = Put(RootNode, Newkey); RootNode->SetValue(": Root"); } ATreeNode* ABinarySearchTrees::Put(ATreeNode* X, int NewKey) { //若是X不存在,創造一個 if (!X) { ATreeNode* NewNode = GetWorld()->SpawnActor<ATreeNode>(ATreeNode::StaticClass()); NewNode->SetValue(NewKey, RouteString); //節點存起來,方便測試 NodeArray.Add(NewNode); //新節點本身算一個節點 NewNode->SetCount(1); return NewNode; } int Temp = CompareTo(NewKey, X->GetKey()); //若是要插入新節點,則新節點的全部父節點都要更新一次 if (Temp < 0) { RouteString.Append(": Left"); X->SetNode(true, Put(X->GetNode(true), NewKey)); } else if (Temp > 0) { RouteString.Append(": Right"); X->SetNode(false, Put(X->GetNode(false), NewKey)); } else { X->SetValue(RouteString); } //更新X節點的Count X->SetCount(1 + Size(X->GetNode(true)) + Size(X->GetNode(false))); return X; } //若是a大於b,返回1;若是a小於b,返回-1;若是相等,返回0 int ABinarySearchTrees::CompareTo(int a, int b) { if (a > b) { return 1; } else if (a < b) { return -1; } else { return 0; } } //尋找最小值 int ABinarySearchTrees::FindMin() { //從根節點開始比較 ATreeNode* X = FindMin(RootNode); if (X) return X->GetKey(); return 0; } //尋找擁有最小值的節點 ATreeNode* ABinarySearchTrees::FindMin(ATreeNode* X) { //當節點存在時 while (X) { //若是左節點存在,繼續循環 if (X->GetNode(true)) { X = X->GetNode(true); } //若是右節點不存在,這個節點就是最小值 else { return X; } } return X; } int ABinarySearchTrees::FindMax() { //從根節點開始比較 ATreeNode* X = FindMax(RootNode); if (X) return X->GetKey(); return 0; } //尋找擁有最大值的節點 ATreeNode* ABinarySearchTrees::FindMax(ATreeNode* X) { //當節點存在時 while (X) { //若是右節點存在,繼續循環 if (X->GetNode(false)) { X = X->GetNode(false); } //若是右節點不存在,這個節點就是最小值 else { return X; } } return X; } //給定一個數字,尋找最接近它的key(比它小) int ABinarySearchTrees::FindFloor(int InputKey) { //從根節點開始比較 ATreeNode* X = FindFloor(RootNode,InputKey); if (X) return X->GetKey(); return 0; } ATreeNode* ABinarySearchTrees::FindFloor(ATreeNode* X, int InputKey) { //若是X節點不存在,就別繼續下去了 if (!X) return nullptr; int Temp = CompareTo(InputKey, X->GetKey()); //若是存在節點的key與輸入值相等,則這個節點就是最接近它了 if (Temp == 0) return X; //若是節點的key比較大,則去找它的左節點,直到找到小於等於輸入值的節點爲止 if (Temp < 0) return FindFloor(X->GetNode(true), InputKey); //若是節點的key比較小,則要找的節點可能在它的右節點的左端 ATreeNode* T = FindFloor(X->GetNode(false), InputKey); //若是找到了T,則說明找到了,返回T;若是找不到,說明X已是最接近的了,返回X if (T) return T; else return X; } //給定一個數字,尋找最接近它的key(比它大) int ABinarySearchTrees::FindCeiling(int InputKey) { //從根節點開始比較 ATreeNode* X = FindCeiling(RootNode, InputKey); if (X) return X->GetKey(); return 0; } ATreeNode* ABinarySearchTrees::FindCeiling(ATreeNode* X, int InputKey) { //若是X節點不存在,就別繼續下去了 if (!X) return nullptr; int Temp = CompareTo(InputKey, X->GetKey()); //若是存在節點的key與輸入值相等,則這個節點就是最接近它了 if (Temp == 0) return X; //若是節點的key比較小,則去找它的右節點,直到找到大於等於輸入值的節點爲止 if (Temp > 0) return FindCeiling(X->GetNode(false), InputKey); //若是節點的key比較大,則要找的節點可能在它的左節點的左端 ATreeNode* T = FindCeiling(X->GetNode(true), InputKey); //若是找到了T,則說明找到了,返回T;若是找不到,說明X已是最接近的了,返回X if (T) return T; else return X; } int ABinarySearchTrees::Size(ATreeNode* X) { //若是節點不存在,返回0 if (!X) return 0; //若是節點存在,返回Count return X->GetCount(); } //求有多少個數字少於給定數字 int ABinarySearchTrees::Rank(int InputKey) { return Rank(InputKey, RootNode); } int ABinarySearchTrees::Rank(int InputKey, ATreeNode* X) { //若是節點不存在,返回0 if (!X) return 0; int Temp = CompareTo(InputKey, X->GetKey()); //若是給定數字比X的key小,則去X的左邊去找比給定數字小的數字 if (Temp < 0) return Rank(InputKey, X->GetNode(true)); //若是給定數字比X的key大,則X和X的左節點都比給定數字小,把它們算上後,去X的右節點找是否還有比給定數字小的數字 else if (Temp > 0) return 1 + Size(X->GetNode(true)) + Rank(InputKey, X->GetNode(false)); //由於右節點都比X大,而X的Key與給定數字相等,故比給定數字小的數字都在X的左節點裏 else return Size(X->GetNode(true)); } void ABinarySearchTrees::InorderTraversal() { OrderNodeArray.Empty(); Inorder(RootNode); } void ABinarySearchTrees::Inorder(ATreeNode* X) { if (!X) return; //先去加X的左節點 Inorder(X->GetNode(true)); //再加X OrderNodeArray.Add(X->GetKey()); //最後加X的右節點 Inorder(X->GetNode(false)); } //刪除最小的節點 void ABinarySearchTrees::DeleteMin() { RootNode = DeleteMin(RootNode); } ATreeNode* ABinarySearchTrees::DeleteMin(ATreeNode* X) { //若是X的左節點不存在,說明已經找到最小值了,刪除它,返回它的右節點 if (!X->GetNode(true)) { ATreeNode* TempNode = X->GetNode(false); NodeArray.Remove(X); X->Destroy(); return TempNode; } //刪除最小值後,把它的右節點和上一個節點連上 X->SetNode(true, DeleteMin(X->GetNode(true))); //更新節點數 X->SetCount(1 + Size(X->GetNode(true)) + Size(X->GetNode(false))); return X; } void ABinarySearchTrees::Delete(int InputKey) { RootNode = Delete(RootNode, InputKey); } ATreeNode* ABinarySearchTrees::Delete(ATreeNode* X, int InputKey) { if (!X) return nullptr; int Temp = CompareTo(InputKey, X->GetKey()); //尋找要刪除的節點,只要刪了一個節點,它上面的全部節點都要更新一次,因此是SetNode if (Temp < 0) X->SetNode(true, Delete(X->GetNode(true), InputKey)); else if (Temp > 0) X->SetNode(false, Delete(X->GetNode(false), InputKey)); //找到要刪除的節點了 else { //若是要刪除的節點只有一個子節點或沒有,那好辦,只需把那個子節點替代它就好 if (!X->GetNode(false)) { ATreeNode* TempNode = X->GetNode(true); NodeArray.Remove(X); X->Destroy(); return TempNode; } if (!X->GetNode(true)) { ATreeNode* TempNode = X->GetNode(false); NodeArray.Remove(X); X->Destroy(); return TempNode; } //若是要刪除的節點有兩個個子節點,從它的右邊找一個最小的節點來替代它 ATreeNode* T = X; X = FindMin(T->GetNode(false)); X->SetNode(false, DeleteMin(T->GetNode(false))); X->SetNode(true, T->GetNode(true)); NodeArray.Remove(T); T->Destroy(); } //更新節點數 X->SetCount(Size(X->GetNode(true)) + Size(X->GetNode(false)) + 1); return X; }