一、定義與性質
定義
二叉排序樹(Binary Sort Tree)又稱二叉尋找(搜尋)樹(Binary Search Tree)。其定義為:二叉排序樹或者是空樹.
性質
(1) 二叉排序樹中任一結點x,其左(右)子樹中任一結點y(若存在)的關鍵字必小(大)於x的關鍵字。
(2) 二叉排序樹中,各結點關鍵字是惟一的。
注意:實際應用中,不能保證被尋找的資料集中各元素的關鍵字互不相同,所以可將二叉排序樹定義中BST性質(1)裡的"小於"改為"大於等於",或將BST性質(2)裡的"大於"改為"小於等於",甚至可同時修改這兩個性質。
(3) 按中序遍曆該樹所得到的中序序列是一個遞增有序序列。
二、插入與刪除
插入與刪除操作是二叉排序樹中最常用也是最重要的兩個操作。
插入過程是:
(a)若二叉排序樹T為空白,則為待插入的關鍵字key申請一個新結點,並令其為根;
(b)若二叉排序樹T不為空白,則將key和根的關鍵字比較:
(i)若二者相等,則說明樹中已有此關鍵字key,無須插入。
(ii)若key<T→key,則將key插入根的左子樹中。
(iii)若key>T→key,則將它插入根的右子樹中。
子樹中的插入過程與上述的樹中插入過程相同。如此進行下去,直到將key作為一個新的葉結點的關鍵字插入到二叉排序樹中,或者直到發現樹中已有此關鍵字為止。
刪除過程:
(1) 進行尋找
尋找時,令p指向當前訪問到的結點,parent指向其雙親(其初值為NULL)。若樹中找不到被刪結點則返回,否則被刪結點是*p。
(2) 刪去*p。
刪*p時,應將*p的子樹(若有)仍串連在樹上且保持BST性質不變。按*p的孩子數目分三種情況進行處理。
刪除*p結點的三種情況
a.*p是葉子(即它的孩子數為0)
無須串連*p的子樹,只需將*p的雙親*parent中指向*p的指標域置空即可。
b.*p只有一個孩子*child
只需將*child和*p的雙親直接連接後,即可刪去*p。
注意:*p既可能是*parent的左孩子也可能是其右孩子,而*child可能是*p的左孩子或右孩子,故共有4種狀態。
c.*p有兩個孩子
先令q=p,將被刪結點的地址儲存在q中;然後找*q的中序後繼*p,並在尋找過程中仍用parent記住*p的雙親位置。*q的中序後繼*p一定是*q的右子樹中最左下的結點,它無左子樹。因此,可以將刪去*q的操作轉換為刪去的*p的操作,即在釋放結點*p之前將其資料複製到*q中,就相當於刪去了*q。
三、代碼清單
#include<stdio.h>#include<stdlib.h>#define maxSize 20 #define maxWidth 20 typedef int KeyType; //假定關鍵字類型為整數typedef struct node { //結點類型KeyType key; //關鍵字項struct node *lchild,*rchild;//左右孩子指標} BSTNode,BSTree;//typedef BSTNode *BSTree; //BSTree是二叉排序樹的類型//先序遍曆 void preOrder(BSTree *BT) { if(BT!= NULL) { printf("%d",BT->key); preOrder(BT->lchild); preOrder(BT->rchild); } } //中序遍曆 void inOrder(BSTree *BT) { if(BT!= NULL) { inOrder(BT->lchild); printf("%d",BT->key); inOrder(BT->rchild); } } //後序遍曆 void postOrder(BSTree *BT) { if(BT!= NULL) { postOrder(BT->lchild); postOrder(BT->rchild); printf("%d",BT->key); } } //層次法列印樹 void dispTree(BSTree *BT) { BSTree *stack[maxSize],*p; int level[maxSize][2],top,n,i,width=4; if(BT!=NULL) { printf("Display a tree by hollow means.\n"); top=1; stack[top]=BT;//push root point to stack. level[top][0]=width; while(top>0) { p=stack[top]; n=level[top][0]; for(i=1;i<=n;i++) printf(" "); printf("%d",p->key); for(i=n+1;i<maxWidth;i+=2) printf("--"); printf("\n"); top--; if(p->rchild!=NULL) { top++; stack[top]=p->rchild; level[top][0]=n+width; level[top][1]=2; } if(p->lchild!=NULL) { top++; stack[top]=p->lchild; level[top][0]=n+width; level[top][1]=1; } } } } /* 向二叉排序樹中加入一個結點 要改變指標,需要傳遞指標的指標*/int InsertNode(BSTree **tree, KeyType key){BSTNode *p= NULL, *parent = NULL;BSTNode *pNewNode = (BSTNode *)malloc(sizeof(BSTNode));if (pNewNode==NULL){return -1;}/* 建立結點賦值,特別是左右子結點指標要賦值為NULL */pNewNode->key = key;pNewNode->lchild = NULL;pNewNode->rchild = NULL;/* 二叉排序樹是空樹 */if (*tree==NULL){*tree = pNewNode;return 0;}else{p = *tree;/* 尋找插入位置 */while (NULL != p){/* key值已在二叉排序樹中 */if (p->key == key){return 0;}else{parent = p;p = (p->key < key) ? p->rchild : p->lchild;}}if (parent->key < key){parent->rchild = pNewNode;}else{parent->lchild = pNewNode;}return 0;}}//刪除節點 /* 通過值尋找並刪除一個結點 */ int delNode(BSTree **tree, KeyType key) { BSTNode *p = NULL, *q = NULL, *parent = NULL, *child = NULL; p = *tree; /* parent為NULL表示根結點的父親為NULL */ while (NULL != p) { if (p->key == key) { break; } else { parent = p; p = (p->key < key) ? p->rchild : p->lchild; } } /* p為NULL時, 表示沒有找到結點值為key的結點 */ if (NULL == p) { return 0; } /* p, q現在都是儲存了待刪結點指標 */ q = p; /* 待刪結點有兩個兒子結點,進行一下轉化 */ if (NULL != p->lchild && NULL != p->rchild) {//找中序後繼,先右拐,然後左走到底 parent = p; p = p->rchild; while (NULL != p->lchild) { parent = p; p = p->lchild; } /* p中儲存了待刪結點右子樹中最左下的結點指標, parent中就儲存了該結點父親指標 */ child = p->rchild; } /* parent儲存待刪結點的父親結點指標, child儲存了待刪結點的兒子結點 //實際刪除的是待刪節點的直接後繼,下面是刪除直接後繼的過程,(待刪結點至多隻有一個兒子, 有兩個會轉化為0個或1個右結點) */ // 待刪結點是根結點,且只有一個兒子 if (NULL == parent) {if(p->lchild!=NULL) *tree = p->lchild;else *tree = p->rchild; } else { /*待刪結點是父親結點的左兒子*/ if (parent->lchild == p) { parent->lchild = child; } else { parent->rchild = child; }//將實際刪除的節點的key值賦給原先要刪除的節點 if (p != q) { q->key = p->key; } } free(p); return 0; }//二叉排序樹尋找BSTNode* SearchBST(BSTree *T,KeyType key){ //在二叉排序樹T上尋找關鍵字為key的結點,成功時返回該結點位置,否則返回NUllif(T==NULL) //遞迴的終結條件return NULL; //T為空白,尋找失敗;if(key==T->key)//成功,返回找到的結點位置{printf("Got it!");return T;}if(key<T->key)return SearchBST(T->lchild,key);elsereturn SearchBST(T->rchild,key);//繼續在右子樹中尋找} //SearchBSTint main(){int n;BSTree *B=NULL;printf("Input number to initialize a BSTree:");while(1){scanf("%d",&n);if(n==0) break;InsertNode(&B, n);}dispTree(B); printf("PreOrder:");preOrder(B);printf("\n");printf("Search a node:");scanf("%d",&n);SearchBST(B,n);printf("\n");printf("Delete a node:");scanf("%d",&n);delNode(&B,n);dispTree(B); printf("PreOrder:");preOrder(B);printf("\n");return 1;}
運行結果:
參考:http://www.cnblogs.com/ljphhj/archive/2012/02/25/2367821.html
http://blog.csdn.net/zhongjiekangping/article/details/4564293