二叉排序樹(BST)構造與應用
本文取自《數據結構與算法》(C語言版)(第三版)。出版社是清華大學出版社。
源碼是VC++ 6.0上可運行程序,我挪到了VS2010中運行。
在VS2010中新建C++ Win32 控制台應用程序項目,創建結果截圖:
二叉排序樹(BST):又稱二叉查找樹,其定義為:二叉排序樹或者是空樹,或者是滿足下面性質的二叉樹。
(1) 若它的左子樹非空。則左子樹上全部記錄的keyword均小於根記錄的值。
(2) 若它的右子樹非空,則右子樹上全部記錄的keyword均大於根記錄的值。
(3) 左、右子樹本身又各是一棵二叉排序樹。
按中序遍歷BST所得到的中序序列是一個遞增有序序列。
二叉排序樹的類型定義:
typedef struct BSTNode { KeyType key; //數據域 BSTNode *lchild; BSTNode *rchild; }1.二叉排序樹的插入操作
(1)假設二叉排序樹T為空,則創建一個keyword為k的結點。將其作為根結點。
(2)否則將k和根結點的keyword進行比較,假設相等則返回,假設k小於根結點的keyword則插入根結點的左子樹中,否則插入根結點的右子樹中。
二叉排序樹的插入算法:
int InsertBST(BSTNode *p, KeyType k) { if(p==NULL) { p=(BSTNode*)malloc(sizeof(BSTNode)); p->key=k; p->lchild=p->rchild=NULL; return 1; } else if(k==p->key) return 0; else if(k<p->key) return InsertBST(p->lchild, k); else return InsertBST(p->rchild, k); }二叉排序樹的生成算法:
BSTNode *CreateBST(KeyType A[], int n) { BSTNode *bt=NULL; int i=0; while(i<n) { InsertBST(bt, A[i]); i++; } return bt; }演示樣例:輸入{50,16,56,52,8}生成二叉排序樹
2.二叉排序樹的查找操作
首先將須要查找的值與根結點比較,假設相等則查找成功,算法終止。假設比根結點小則左子樹中查找,假設比根結點大則到右子樹查找。
二叉排序樹的查找算法的遞歸形式
BSTree SearchBST(BSTree t, int k) { if(t==null || k==t->key) return t; else if(k<t->key) return SearchBST(t->lchild, k); else return SearchBST(t->rchild, k); }二叉排序樹的查找算法的非遞歸形式
BSTree SearchBST2(BSTree t, int k) { BSTree p=t; while(p!=null && p->key!=k) { if(k<p->key) p=p->lchild; else p=p->rchild; } return p; }
查找過程演示圖:
3.二叉排序樹的刪除操作
刪除二叉排序樹的某一個結點的過程例如以下:1)查找待刪除的結點
查找結點時,令*p指向其訪問到的結點,*f指向其雙親結點。若樹中找不到被刪結點時返回NULL,否則被刪除結點是*p,返回*p。
2)刪除結點
如果要刪除二叉排序樹中的一個結點*p,其雙親結點為*f,則刪除結點*p時,需考慮下面3種情況:
(1)*p為葉子結點。
在這樣的情況下,能夠將*p結點直接刪除。
p為左子樹:
f->lchild=NULL;
free(p);
p為右子樹:
f->rclild=NULl;
free(p);
操作示意圖例如以下:
對於這樣的情況,能夠直接將*p的左子樹或右子樹與其雙親結點*f相連,然后刪除*p。
p為f的左孩子。p的左子樹非空:
f->lchild=p->lchild;
free(p);
p為f的左孩子。p的右子樹非空:
f->lchild=p->rchild;
free(p);
p為f的右孩子,p的左子樹非空:
f->rchild=p->lchild;
free(p);
p為f的右孩子,p的右子樹非空:
f->rchild=p->rchild;
free(p);
操作示意圖例如以下:
方法一:設*s為*p結點在中序序列中的直接前驅。將*p的左子樹改為*f的左子樹,將*p的右子樹改為*s的右子樹。
f->lchild=p->lchild;
s->rchild=p->rchild;
free(p);
操作示意圖例如以下:
方法二:用*p結點在中序序列中的直接前驅(或后繼)*s取代*p,然后再從二叉排序樹中將*s刪除。
這時假設*s為*p的直接前驅,則*s僅僅有左子樹(或者沒有孩子),則刪除*s能夠依照刪除*p的其余兩種情況處理。假設*s為*p的直接后繼,則*s僅僅有右子樹(或者沒有孩子)。刪除*s同理能夠依照刪除*p的其余兩種情況處理。
附錄
A.二叉排序樹的構造算法:
注:判定一棵二叉樹是二叉排序樹能夠採用中序遍歷算法將樹上的頂點輸出。假設得到的中序序列是有序的。則說明這棵二叉樹是二叉排序樹,否則不是二叉排序樹。#include<stdio.h> #include<stdlib.h> #define MAX 100 typedef struct tnode { int data; struct tnode *lchild, *rchild; }TNODE; void create(); void insert(int m); //插入二叉排序樹的結點 void inOrder(TNODE *ptr); //中序遍歷 TNODE *root=NULL; void inOrder(TNODE *ptr) { if(ptr!=NULL) { inOrder(ptr->lchild); printf("%d ", ptr->data); inOrder(ptr->rchild); } } void create() { int n, i; int k[MAX]; printf("Please input the node number:\n"); scanf("%d", &n); for(i=0; i<n; i++) scanf("%d",&k[i]); for(i=0; i<n; i++) insert(k[i]); } void insert(int m) { TNODE *p1, *p2; if(root==NULL) { root=(TNODE *)malloc(sizeof(TNODE)); root->data=m; root->lchild=root->rchild=NULL; } else { p1=root; while(m!=p1->data) { if((m<p1->data) && (p1->lchild!=NULL)) p1=p1->lchild; else if((m>p1->data) && (p1->rchild!=NULL)) p1=p1->rchild; else if((m<p1->data) && (p1->lchild==NULL)) { p2=(TNODE *)malloc(sizeof(TNODE)); p2->data=m; p2->lchild=p2->rchild=NULL; p1->lchild=p2; return; } else if((m>p1->data) && (p1->rchild==NULL)) { p2=(TNODE *)malloc(sizeof(TNODE)); p2->data=m; p2->lchild=p2->rchild=NULL; p1->rchild=p2; return; } } } } int main() { create(); printf("\n"); inOrder(root); printf("\n"); return 0; }Ctrl+F5執行SortTree.cpp輸出結果例如以下:
B.求出二叉排序樹T中小於x的最大元素和大於x的最小元素
在二叉排序樹中。一個小於樹中某個結點的最大元素,是在中序序列中這個結點的直接前驅;大於這個結點的最小元素,是在中序序列中這個結點的直接后繼。
其程序例如以下:
#include<stdio.h> #include<stdlib.h> #define MAX 100 typedef struct tnode { int data; struct tnode *lchild, *rchild; }TNODE; int last=0; void create(); void insert(int m); //插入二叉排序樹的結點 void findMaxMin(int aim, TNODE *ptr); TNODE *root=NULL; void findMaxMin(int aim, TNODE *ptr) { if(ptr!=NULL) { findMaxMin(aim, ptr->lchild); if(last<aim && ptr->data>=aim) //找到小於aim的最大元素 printf("a=%d\n",last); if(last<=aim && ptr->data>aim) //找到大於aim的最小元素 printf("b=%d\n",ptr->data); last=ptr->data; findMaxMin(aim, ptr->rchild); } } void create() { int n, i; int k[MAX]; printf("Please input the node number:\n"); scanf("%d", &n); for(i=0; i<n; i++) scanf("%d",&k[i]); for(i=0; i<n; i++) insert(k[i]); } void insert(int m) { TNODE *p1, *p2; if(root==NULL) { root=(TNODE *)malloc(sizeof(TNODE)); root->data=m; root->lchild=root->rchild=NULL; } else { p1=root; while(m!=p1->data) { if((m<p1->data) && (p1->lchild!=NULL)) p1=p1->lchild; else if((m>p1->data) && (p1->rchild!=NULL)) p1=p1->rchild; else if((m<p1->data) && (p1->lchild==NULL)) { p2=(TNODE *)malloc(sizeof(TNODE)); p2->data=m; p2->lchild=p2->rchild=NULL; p1->lchild=p2; return; } else if((m>p1->data) && (p1->rchild==NULL)) { p2=(TNODE *)malloc(sizeof(TNODE)); p2->data=m; p2->lchild=p2->rchild=NULL; p1->rchild=p2; return; } } } } int main() { int toBeFind; create(); printf("\n"); printf("Input the record to be finded! \n"); scanf("%d", &toBeFind); findMaxMin(toBeFind, root); printf("\n"); return 0; }Ctrl+F5執行SortTree1.cpp輸出結果例如以下: