(原創)像極了愛情的詳解排序二叉樹,一秒get
排序二叉樹(建立、查找、刪除)
二叉樹我們已經非常熟悉了,但是除了尋常的儲存數據、遍歷結構,我們還能用二叉樹做什麽呢?
我們都知道不同的遍歷方式會對相同的樹中產生不同的序列結果,排序二叉樹就是利用二叉樹的遍歷特征實現的特殊樹種,也叫二叉查找樹。
- 排序二叉樹從根結點起的每一個結點的左子樹元素均小於其自身,右子樹元素值均大於其自身
- 即任何結點的值均大於其左子樹所有元素,均小於其右子樹所有元素
如:就是一個排序二叉樹,直觀的一批,從子樹到根結點,永遠符合左小右大的規則(中序遍歷)
Ⅰ、結構定義
排序二叉樹的定義與一般二叉樹無異
typedef struct BiTree{int item; struct BiTree *lchild,*rchild; }BiTree;
Ⅱ、排序二叉樹的查找
我們先來看一下排序二叉樹的查找實現,因為插入在排序二叉樹中是實現後續建立、刪除結點的基礎,因為結點帶有順序,故而遍歷條件有所改變,代碼如下:
int searchnode(BiTree *t, int key) { if(!t) return 0; if(t->item == key) { return 1; } else { if(t->item > key) return searchnode(t->lchild,key); if(t->item < key) return searchnode(t->rchild,key); } }
清爽遞歸,不解釋
Ⅲ、二叉排序樹的插入
void insertbitree(BiTree **t, int value) { if(!searchnode(*t,value)) { if(*t == NULL) {*t = (BiTree *)malloc(sizeof(BiTree)); (*t)->item = value; (*t)->lchild = NULL; (*t)->rchild = NULL; } else { if((*t)->item > value) insertbitree(&((*t)->lchild), value); else insertbitree(&((*t)->rchild), value); } } }
這個插入上來先判斷一哈我們現有的樹裏面有沒有這個元素,如果有就不會進入循環,至於插入操作的框架也基本符合中序遍歷的操作,只是加上了判斷大小
Ⅳ、二叉排序樹刪除結點(HARD)
輕松愉快的建立、查找排序二叉樹的操作完成之後,我們來看看比較困難的刪除排序二叉樹結點的操作。為什麽說它困難呢,相比插入或者查找,刪除面對的是一個已經成型的樹,我們不僅要考慮怎樣去掉這個結點,還要想到按照中序以及數字大小將原有結點按序放到正確位置。
好的,我們先來考慮一下我們可能刪除哪幾種結點:
第一類:待刪除結點只有左子樹,沒有右子樹,可以想見,這種情況下只需要把後續的左子樹接到待刪除結點的上一個結點上,再釋放待刪除結點的空間就OK
第二類:帶刪除結點只有右子樹,沒有左子樹,跟第一類一個道理,這樣的操作只需要三行就解決,但是棘手的問題總在短暫的輕松過後
第三類:這一類情況就是大魔王遼,左右孩子一個不缺,手心手背都是肉,哪個也不能少,怎麽解決這個問題呢?讓我們來看一個例子。
看這個醜不拉嘰的排序二叉樹,非常體現中序遍歷特點
現在我們要刪除 34 這個結點,就是我們剛才說的那種第三類情況,左右均有結點,這個時候,我們有這兩種方法闊以達成目的
第一種:姑且叫他 犧牲前驅法 ,我們要去掉 34 ,就要把他的前驅拿來頂替這個位置,保持二叉排序樹的序,然後當然要檢測一下,如果犧牲的這個前驅點(在我們這裏是 33 )有子樹,還需要把子樹和上一級連上(如32),這是第一種方法
- 用直接前驅 33 替換 34
- 刪除原有的 33 結點
- 把結點 32 ,移到原 33 位置
第二種:相信你也猜到了,犧牲後繼法,反正兄弟兩個要挑一個頂上去,讓我們看一哈在這個例子中,怎麽個犧牲後繼
35 已經被我們放上來遼
- 用直接後繼 35 替換 34
- 刪除結點 35
因為這裏的 35 煢煢孑立,沒兒沒女,所以這個例子的這裏不需要連接子樹,但是千萬註意不要認為所有的替換後繼法都不用管子樹
好的,方法講明白了遼,我們代碼實現一哈
int Delete(BiTree **t) { BiTree *s,*q; if((*t) -> lchild == NULL)//左子樹空的情況 { q = *t; *t = (*t)->lchild; free(q); } else if( (*t) -> rchild == NULL)//右子樹為空的情況 { q = *t; *t = (*t)->rchild; free(q); } else //左右子數均為空 { q = *t; s = (*t)->lchild; while(s->rchild)//循環找到直接前驅 { q = s; s = s->rchild; } (*t) -> item = s -> item; //結點數據替換 if(q != *t) //接原有左右子樹 q->rchild = s->lchild; else q->lchild = s->lchild; free(s); } return 1; } int DeleteBST(BiTree **T, int key) { if (!*T) return 0; else { if (key == (*T)->item) return Delete(T); else if (key < (*T)->item) return DeleteBST(&(*T)->lchild, key); else return DeleteBST(&(*T)->rchild, key); } return 1; }
解讀見註釋
測試用主函數部分:
int main() { int i; BiTree *t = NULL; int value[] = {12,24,88,3,64,99,71,64,10,8}; for(i = 0; i < 10; i++) insertbitree(&t,value[i]); printf("建立序列為:\n"); lar(t); printf("\n"); printf("刪除結點88,結果為:\n"); DeleteBST(&t,88); lar(t); printf("\n"); return 0; }
呼~完畢
(原創)像極了愛情的詳解排序二叉樹,一秒get