1. 程式人生 > >二叉搜尋樹(二叉排序樹)

二叉搜尋樹(二叉排序樹)

內容和程式碼參考殷人昆版的《資料結構》

二叉搜尋樹也稱為二叉排序樹,二叉搜尋樹要麼是空樹,要麼具有如下性質:

(1)每個結點都有一個作為搜尋依據的結點值,並且每個結點值互不相同;

(2)左子樹(如果存在)上的所有結點值都小於根結點的值;

(3)右子樹(如果存在)上的所有結點值都大於根結點的值;

(4)左子樹和右子樹也是二叉搜尋樹。

對一棵二叉搜尋樹進行中序遍歷,可以從小到大的將結點值排列起來。這裡注意的是:同一組資料根據不同的排列可以構建出多棵不同的二叉搜尋樹。對於有n個關鍵碼的集合,有n!中不同的排列,可以構成種不同的二叉搜尋樹。

二叉搜尋樹搜尋、插入、刪除操作的平均時間代價為O(logn).

二叉搜尋樹的結構體定義:


//結構體的類定義
template<class T>
struct BSTree{
	T data;
	BSTree* left, right;
	BSTree():left(NULL),right(NULL){};
};

二叉搜尋樹的查詢:(注意:我看其他的資料程式碼,有的查詢操作返回的是void,如果返回void就不能知道是否返回成功;查詢操作應該返回的查詢到的樹結點)

//查詢
template<class T>
BSTree* search(const T x, BSTree* ptr){
	if(ptr == NULL)return NULL;   //搜尋失敗
	else if(x < ptr->data)search(x, ptr->left);
	else if(x > ptr->data)search(x, ptr->right);
	else return ptr;  //搜尋成功
}

二叉搜尋樹的插入:(注意:向二叉搜尋樹中插入一個元素,必須先檢查這個元素是否在樹中已經存在)

//插入
template<class T>
bool insert(const T x, BSTree* & ptr){
	if(ptr == NULL){    //新結點作為葉結點插入
		ptr = new BSTree(x);   //建立新的結點
		if(ptr == NULL){cerr<<"out of space"<<endl; exit(-1)};
		return true;
	}
	else if(x < ptr->data)insert(x,ptr->left);   //向左子樹搜尋
	else if(x > ptr->data)insert(x,ptr->right);  //向右子樹搜尋
	else return false;   //這個表明要插入的元素在樹中已經存在,返回false
}


二叉搜尋樹的刪除:(二叉搜尋樹的刪除有三種情況:1、結點的右子樹為空,則用左子樹填補;2、結點的左子樹為空,則用右子樹填補;3、結點的左右子樹都不為空,則在它的右子樹中序遍歷下的第一個結點來填補,然後遞迴地處理右子樹)

//刪除
template<class T>
bool remove(const T x, BSTree* & ptr){
	BSTree* temp;
	if(ptr != NULL){
		if(x < ptr->data)remove(x,ptr->left);
		else if(x > ptr->data)remove(x, ptr->right);
		else if(ptr->left != NULL && ptr->right != NULL){  //左右子樹均不為空
			temp = ptr->right;
			while(temp->left != NULL)temp = temp->left;  //用它的右子樹中序遍歷下的第一個結點來填補
			ptr->data = temp->data;
			remove(ptr->data, ptr->right);  //然後要刪除被拿來填補的那個結點,遞迴的處理右子樹
		}
		else{
			temp = ptr;
			if(ptr->left == NULL)ptr = ptr->right;
			else ptr = ptr->left;
			delete temp;
			return true;
		}
	}
	reurn false;
}



以上的操作都用遞迴的方式實現,我覺得遞迴的方式效率雖然不高,但看起來真的很舒服啊=_=,所以就直接用遞迴的方式了,以後有時間再用非遞迴的方式實現一遍。