數據結構(六)查找---二叉搜索樹(排序樹)
阿新 • • 發佈:2018-08-20
color 父節點 img hid warning close status 效率 spa
前提
前面的查找我們都是靜態查找,因為數據集是有序存放,查找的方法有多種,可以使用折半,插值,斐波那契等,但是因為有序,在插入和刪除操作上的效率並不高。
這時我們就需要一種動態查找方法,既可以高效實現查找,又可以使得插入和刪除效率不錯,這時我們可以考慮二叉排序樹
二叉排序樹
一:定義
又稱為二叉搜索樹(查找樹),是一棵樹,可以為空,但是需要滿足以下性質:
1.非空左子樹的所有鍵值小於其根節點的鍵值 2.非空右子樹的所有鍵值大於其根節點的鍵值 3.左右子樹都是二叉搜索樹
二:操作
查找
/* BiTree T 我們要搜索的二叉樹 ElemType key我們要搜索的關鍵字 BiTree F 記錄下我們的當前搜索子樹的雙親結點 BiTree* P 當我們插入之前,會先搜索是否存在數據,若存在,不插入,若不存在,我們通過這個可以獲取我們要插入的位置,直接插入即可*/
Status SearchBST(BiTree T, ElemType key, BiTree F, BiTree* P)
/* BiTree T 我們要搜索的二叉樹 ElemType key我們要搜索的關鍵字 BiTree F 記錄下我們的當前搜索子樹的雙親結點 BiTree* P 當我們插入之前,會先搜索是否存在數據,若存在,不插入,若不存在,我們通過這個可以獲取我們要插入的位置,直接插入即可 */ Status SearchBST(BiTree T, ElemType key, BiTree F, BiTree* P) { if (!T) {View Code*P = F; //若是未找到則返回父節點位置 return FALSE; } else { if (T->data == key) { *P = T; //若是找到則P返回該結點位置 return TRUE; } else if (T->data < key) return SearchBST(T->rchild, key, T, P); else returnSearchBST(T->lchild, key, T, P); } }
插入
Status InsertBST(BiTree* T, int key)
由於二叉搜索樹的特殊性質確定了二叉搜索樹中每個元素只可能出現一次,所以在插入的過程中如果發現這個元素已經存在於二叉搜索樹中,就不進行插入。否則就查找合適的位置進行插入。
第一種情況:樹為空--->直接插入,返回TRUE
第二種情況:要插入的元素已經存在,如果在二叉搜索樹中已經存在該元素,則不再進行插入,直接return false;
第三種情況:能夠找到合適的位置,通過上面搜索函數搜索返回其父節點,直接插入即可
Status InsertBST(BiTree* T, int key) { BiTree P,s; if (!T) return ERROR; if (!SearchBST(*T, key, NULL, &P)) { //沒有查找到有重復數據,獲取到了應該插入的位置 s = (BiTree)malloc(sizeof(BiTNode)); s->data = key; s->lchild = s->rchild = NULL; if (!P) //空樹 *T = s; else if (key < P->data) //插入左子樹 P->lchild = s; else P->rchild = s; return OK; } else return ERROR; }View Code
刪除(上面兩種比較容易,不再詳說,刪除的情況較多)
Status DeleteBST(BiTree* T, int key)
1.刪除的結點是葉子結點,直接刪除(直接判斷左右指針是否存在)
2.刪除的結點只有左孩子,直接讓該結點的父節點指向其左孩子
3.刪除的結點只有右孩子,直接讓該結點的父節點指向其右孩子
註意:其實1可以由2,3代替,因為2,3一起就包括了左右子樹都不存在的情況,其中2,3指向的左右子樹為NULL就是1情況
4.刪除的結點含有左右孩子,需要再進行分類討論(重點)<這裏考慮了一種,就是使用右子樹最小來進行替換,還可以選擇左子樹最大來替換>
註意:上面兩種情況可以歸為一種,就是第二張圖片那樣,直接讓黃色父節點左指針指向其綠色結點的右孩子。
第三種情況:是較為特殊的,綠色(不存在左子樹)的父節點直接是要刪除的紅色結點,我們要使得其新的結點右指針指向原來綠色的右指針
Status Delete(BiTree* T) { BiTree q,f; if (!*T) return ERROR; if (!(*T)->lchild) //若是左子樹不存在,我們只需要接到右子樹 { q = *T; *T = (*T)->rchild; free(q); } else if (!(*T)->rchild) //若右子樹不存在,接入左子樹 { q = *T; *T = (*T)->lchild; free(q); } else //兩邊都存在,我們可以選擇將右子樹最小,或者左子樹最大接入,這裏選擇右子樹最小 { f = *T; //f指向q的雙親結點 q = (*T)->rchild; while (q) { f = q; q = q->lchild; //找到右子樹最小,註意其可能存在右子樹,我們要進行保存,接入其父節點 } //將最小的數據更新到根節點處即可,然後記錄最小點處,刪除即可 (*T)->data = q->data; if (f != (*T)) f->lchild = q->rchild; else f->rchild = q->rchild; //當右子樹是一個右斜樹 free(q); } return TRUE; } Status DeleteBST(BiTree* T, int key) { if (!*T) return ERROR; else { if ((*T)->data == key) //找到了,開始刪除 { //刪除該結點,由於要分情況討論,所以另外寫一個函數 } else if ((*T)->data < key) DeleteBST(&(*T)->rchild, key); else DeleteBST(&(*T)->lchild, key); } }View Code
三:代碼實現
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 typedef int Status; typedef int ElemType; typedef struct _BiTNode { ElemType data; struct _BiTNode* lchild, *rchild; }BiTNode,*BiTree; /* BiTree T 我們要搜索的二叉樹 ElemType key我們要搜索的關鍵字 BiTree F 記錄下我們的當前搜索子樹的雙親結點 BiTree* P 當我們插入之前,會先搜索是否存在數據,若存在,不插入,若不存在,我們通過這個可以獲取我們要插入的位置,直接插入即可 */ Status SearchBST(BiTree T, ElemType key, BiTree F, BiTree* P) { if (!T) { *P = F; //若是未找到則返回父節點位置 return FALSE; } else { if (T->data == key) { *P = T; //若是找到則P返回該結點位置 return TRUE; } else if (T->data < key) return SearchBST(T->rchild, key, T, P); else return SearchBST(T->lchild, key, T, P); } } Status InsertBST(BiTree* T, int key) { BiTree P,s; if (!T) return ERROR; if (!SearchBST(*T, key, NULL, &P)) { //沒有查找到有重復數據,獲取到了應該插入的位置 s = (BiTree)malloc(sizeof(BiTNode)); s->data = key; s->lchild = s->rchild = NULL; if (!P) //空樹 *T = s; else if (key < P->data) //插入左子樹 P->lchild = s; else P->rchild = s; return OK; } else return ERROR; } Status Delete(BiTree* T) { BiTree q,f; if (!*T) return ERROR; if (!(*T)->lchild) //若是左子樹不存在,我們只需要接到右子樹 { q = *T; *T = (*T)->rchild; free(q); } else if (!(*T)->rchild) //若右子樹不存在,接入左子樹 { q = *T; *T = (*T)->lchild; free(q); } else //兩邊都存在,我們可以選擇將右子樹最小,或者左子樹最大接入,這裏選擇右子樹最小 { f = *T; //f指向q的雙親結點 q = (*T)->rchild; while (q) { f = q; q = q->lchild; //找到右子樹最小,註意其可能存在右子樹,我們要進行保存,接入其父節點 } //將最小的數據更新到根節點處即可,然後記錄最小點處,刪除即可 (*T)->data = q->data; if (f != (*T)) f->lchild = q->rchild; else f->rchild = q->rchild; //當右子樹是一個右斜樹 free(q); } return TRUE; } Status DeleteBST(BiTree* T, int key) { if (!*T) return ERROR; else { if ((*T)->data == key) //找到了,開始刪除 { //刪除該結點,由於要分情況討論,所以另外寫一個函數 } else if ((*T)->data < key) DeleteBST(&(*T)->rchild, key); else DeleteBST(&(*T)->lchild, key); } } int main() { int i,ret; int a[10] = { 62, 88, 58, 47, 35, 73, 51, 99, 37, 93 }; BiTree T = NULL; BiTree P=NULL; for (i = 0; i < 10;i++) InsertBST(&T, a[i]); ret=SearchBST(T, 47, NULL, &P); if (ret) printf("find node\n"); DeleteBST(&T, 73); ret = SearchBST(T, 47, NULL, &P); if (ret) printf("not find node ,it has deleted\n"); system("pause"); return 0; }
數據結構(六)查找---二叉搜索樹(排序樹)