⼆叉排序樹(Binary Sort Tree),⼜稱爲⼆叉查找樹. 它或者是⼀顆空樹.或者是⼀顆 具備下列性質的⼆叉樹; 若它的左⼦樹不空,則左⼦樹上全部結點的值均⼩於它的根結構的值; 若它的右⼦樹不空,則右⼦樹上的全部結點的值均⼤於它的根結點的值; 它的左右⼦樹也分別是⼆叉排序樹;bash
//1.二叉排序樹--查找 /* 遞歸查找二叉排序樹T中,是否存在key; 指針f指向T的雙親,器初始值爲NULL; 若查找成功,則指針p指向該數據元素的結點,而且返回TRUE; 若指針p指向查找路徑上訪問的最後一個結點則返回FALSE; */ Status SearchBST(BiTree T,int key,BiTree f, BiTree *p){ //若是根節點都是空則返回錯誤 if(!T){ //直接返回雙親結點 *p =f; return FALSE; } if(T->data == key){ //當查找的元素就等於根節點 直接返回根節點 (*p) = T; return TRUE; }else if(key > T->data){ //當查找的元素大於根節點的元素(根據二叉排序樹的特性)直接去右子樹繼續查找並傳入雙親結點 return SearchBST(T->rchild, key, T, p); }else{ //當查找的元素小於根節點的元素(根據二叉排序樹的特性)直接去坐左樹繼續查找並傳入雙親結點 return SearchBST(T->lchild, key, T, p); } return FALSE; } 複製代碼
//2.二叉排序樹-插入 /* 當二叉排序樹T中不存在關鍵字等於key的數據元素時, */ /* 插入key並返回TRUE,不然返回FALSE */ Status InsertBST(BiTree *T, int key) { BiTree p; if(SearchBST(*T, key, NULL, &p)){ //若是元素已經存在則直接返回插入失敗 return FALSE; }else{ BiTree s = (BiNode *)malloc(sizeof(BiNode)); if(!s) return FALSE; s->data = key; s->lchild = s->rchild = NULL; if(p == NULL){ //說明是空樹 *T = s; }else{ //開始判斷當前的值和樹的最後一個結點的大小,大插到右邊,小插左邊 if(p->data > key){ p->lchild = s; }else{ p->rchild = s; } } return TRUE; } } 複製代碼
實現思路 主要分三種狀況markdown
刪除的結點是葉子結點;這種狀況最好處理只要找到對應的結點刪除便可spa
刪除的結點非葉子結點可是僅含有左結點或者右結點;這種狀況只須要將待刪除結點的右結點或者左節點的值和左右結點賦值給待刪除的結點就好如圖刪除的是58這個結點 指針
刪除的結點既有左結點又含有右結點;這種狀況就是找到待刪除結點的左節點,而後一直向下尋找左結點的右結點,而後繼續右結點的右結點,一直往下找直到右結點爲null的結點,則用找到的這個結點替換待刪除的結點,或者說找到待刪除結點的右結點,而後再找右結點的左節點,一直往下找左節點直到找到左節點爲null的結點而後用這個結點替換待刪除的結點,在中序遍歷中這兩個結點分別是待刪除結點的先後兩個結點,用這兩個結點替代待刪除的結點對數的改動最小如圖刪除47這個結點按上述步驟能夠找到37結點和48結點能夠用這兩個結點中的任意一個結點替換待刪除位置的結點 code
實現代碼orm
//3.從二叉排序樹中刪除結點p,並重接它的左或者右子樹; //f Status Delete(BiTree *p){ if((*p)->lchild && (*p)->rchild){ //若是刪除的結點的左子樹和右子樹都不爲空 //找到左子樹的最後一個右結點或者找到右子樹最後一個左節點 //(其實中序遍歷的話這兩個結點恰好是待刪除結點的先後兩個結點) //因此用這兩個結點替換待刪除的結點樹的改動最小 //查找左子樹的最後一個結點 BiTree temp; BiTree s = NULL; temp = (*p)->lchild; while (temp->rchild) { s = temp; temp = temp->rchild; } //開始賦值 (*p)->data = temp->data; if(s){ s->rchild = temp->lchild; } free(temp); }else if((*p)->lchild){ BiTree temp; temp = *p; *p = (*p)->lchild; free(temp); }else if((*p)->rchild){ BiTree temp; temp = *p; *p = (*p)->rchild; free(temp); }else{ *p = NULL; free(*p); } return TRUE; } //4.查找結點,並將其在二叉排序中刪除; /* 若二叉排序樹T中存在關鍵字等於key的數據元素時,則刪除該數據元素結點, */ /* 並返回TRUE;不然返回FALSE。 */ Status DeleteBST(BiTree *T,int key){ //不存在關鍵字等於key的數據元素 if(!*T) return FALSE; else { //找到關鍵字等於key的數據元素 if (key==(*T)->data) return Delete(T); else if (key<(*T)->data) //關鍵字key小於當前結點,則縮小查找範圍到它的左子樹; return DeleteBST(&(*T)->lchild,key); else //關鍵字key大於當前結點,則縮小查找範圍到它的右子樹; return DeleteBST(&(*T)->rchild,key); } } 複製代碼
// // main.c // 二叉排序樹 // // Created by xzkj on 2020/6/3. // Copyright © 2020 TuDou. All rights reserved. // #include <stdio.h> #include "stdlib.h" #define FALSE 0 #define TRUE 1 typedef int Status; typedef struct BiNode{ int data; //數據 struct BiNode *lchild,*rchild; //左孩子和右孩子 }BiNode,*BiTree; //1.二叉排序樹--查找 /* 遞歸查找二叉排序樹T中,是否存在key; 指針f指向T的雙親,器初始值爲NULL; 若查找成功,則指針p指向該數據元素的結點,而且返回TRUE; 若指針p指向查找路徑上訪問的最後一個結點則返回FALSE; */ Status SearchBST(BiTree T,int key,BiTree f, BiTree *p){ //若是根節點都是空則返回錯誤 if(!T){ //直接返回雙親結點 *p =f; return FALSE; } if(T->data == key){ //當查找的元素就等於根節點 直接返回根節點 (*p) = T; return TRUE; }else if(key > T->data){ //當查找的元素大於根節點的元素(根據二叉排序樹的特性)直接去右子樹繼續查找並傳入雙親結點 return SearchBST(T->rchild, key, T, p); }else{ //當查找的元素小於根節點的元素(根據二叉排序樹的特性)直接去坐左樹繼續查找並傳入雙親結點 return SearchBST(T->lchild, key, T, p); } return FALSE; } //2.二叉排序樹-插入 /* 當二叉排序樹T中不存在關鍵字等於key的數據元素時, */ /* 插入key並返回TRUE,不然返回FALSE */ Status InsertBST(BiTree *T, int key) { BiTree p; if(SearchBST(*T, key, NULL, &p)){ //若是元素已經存在則直接返回插入失敗 return FALSE; }else{ BiTree s = (BiNode *)malloc(sizeof(BiNode)); if(!s) return FALSE; s->data = key; s->lchild = s->rchild = NULL; if(p == NULL){ //說明是空樹 *T = s; }else{ //開始判斷當前的值和樹的最後一個結點的大小,大插到右邊,小插左邊 if(p->data > key){ p->lchild = s; }else{ p->rchild = s; } } return TRUE; } } //3.從二叉排序樹中刪除結點p,並重接它的左或者右子樹; //f Status Delete(BiTree *p){ if((*p)->lchild && (*p)->rchild){ //若是刪除的結點的左子樹和右子樹都不爲空 //找到左子樹的最後一個右結點或者找到右子樹最後一個左節點 //(其實中序遍歷的話這兩個結點恰好是待刪除結點的先後兩個結點) //因此用這兩個結點替換待刪除的結點樹的改動最小 //查找左子樹的最後一個結點 BiTree temp; BiTree s = NULL; temp = (*p)->lchild; while (temp->rchild) { s = temp; temp = temp->rchild; } //開始賦值 (*p)->data = temp->data; if(s){ s->rchild = temp->lchild; } free(temp); }else if((*p)->lchild){ BiTree temp; temp = *p; *p = (*p)->lchild; free(temp); }else if((*p)->rchild){ BiTree temp; temp = *p; *p = (*p)->rchild; free(temp); }else{ *p = NULL; free(*p); } return TRUE; } //4.查找結點,並將其在二叉排序中刪除; /* 若二叉排序樹T中存在關鍵字等於key的數據元素時,則刪除該數據元素結點, */ /* 並返回TRUE;不然返回FALSE。 */ Status DeleteBST(BiTree *T,int key){ //不存在關鍵字等於key的數據元素 if(!*T) return FALSE; else { //找到關鍵字等於key的數據元素 if (key==(*T)->data) return Delete(T); else if (key<(*T)->data) //關鍵字key小於當前結點,則縮小查找範圍到它的左子樹; return DeleteBST(&(*T)->lchild,key); else //關鍵字key大於當前結點,則縮小查找範圍到它的右子樹; return DeleteBST(&(*T)->rchild,key); } } int main(int argc, const char * argv[]) { // insert code here... printf("Hello, World!\n"); int i; int a[10]={62,88,58,47,35,73,51,99,37,93}; BiTree T=NULL; for(i=0;i<10;i++) { InsertBST(&T, a[i]); } BiTree p; int statusValue = SearchBST(T, 99, NULL, &p); printf("查找%d是否成功:%d (1->YES/0->NO)\n",p->data,statusValue); statusValue = DeleteBST(&T,93); printf("二叉排序樹刪除93是否成功:%d (1->YES/0->NO)\n",statusValue); statusValue = DeleteBST(&T,47); printf("二叉排序樹刪除47是否成功:%d (1->YES/0->NO)\n",statusValue); statusValue = DeleteBST(&T,12); printf("二叉排序樹刪除12是否成功:%d (1->YES/0->NO)\n",statusValue); statusValue = SearchBST(T, 93, NULL, &p); printf("查找%d是否成功:%d (1->YES/0->NO)\n",93,statusValue); // statusValue = SearchBST(T, 47, NULL, &p); printf("查找%d是否成功:%d (1->YES/0->NO)\n",47,statusValue); statusValue = SearchBST(T, 99, NULL, &p); printf("查找%d是否成功:%d (1->YES/0->NO)\n",99,statusValue); printf("\n"); return 0; } 複製代碼