標籤:
與鏈表不同,樹是一種非線性資料結構。樹中最常用的是二叉樹,二叉樹限制了子樹的數量,也就是每個結點的子樹至多2個,並且這兩個子樹是有順序的。而二叉搜尋樹(二叉尋找樹,二叉排序樹)是指根節點的關鍵字大於左子樹的,而小於右子樹,並且,左右子樹也是一顆二叉搜尋樹。也就是說中序遍曆一顆二叉搜尋樹,它的輸出是從小到大排序好的。
除了普通的二叉搜尋樹之外,還有很多關於它的變形。
二叉平衡搜尋樹,即即是一顆二叉平衡樹,也是一顆搜尋樹,平衡樹即任意一個結點的左子樹的高度與右子樹的高度之差的絕對值不大於1。
紅/黑樹狀結構,也是一種特殊的二叉尋找樹,除了具備尋找樹的特點,它的每個結點上還有一個記錄紅黑顏色的元素。
這裡我們主要討論一般的二叉搜尋樹。
二叉搜尋樹,其實就是一顆特殊的樹,任何適用於樹的演算法都適用於二叉搜尋樹。當然它也是圖,任何適用於圖的演算法也適用於二叉搜尋樹。圖中的深度優先搜尋(DFS)其實就是樹中的前序走訪,廣度優先搜尋(BFS)就是樹中的層序遍曆。當然圖中還有很多其他演算法也都適用於樹。
1、二叉樹的資料結構
typedef struct binSrcTreeNode{ int element; struct binSrcTreeNode *pLeft; struct binSrcTreeNode *pRight;}BSTNode;
2、動態分配一個二叉樹的結點
BSTNode* allocNode(int element){ BATNode *pNode = (BSTNode*)malloc(sizeof(BSTNode)); if(NULL != pNode){ pNode->element = element; pNode->pLeft = NULL; pNode->pRight = NULL; } return pNode;}
3、二叉搜尋樹的尋找
由於二叉搜尋樹是已經排序了的二叉樹,所以可以通過二分尋找來搜尋。先判斷是否等於根節點,如果大於根節點的關鍵字,搜尋右子樹,小於根節點的關鍵字,搜尋左子樹。
bool searchInBSTree(const BSTNode *pRoot,int element,BSTNode **pNode){ if(NULL == pRoot) return false; *pNode = pRoot; if(pRoot->element == element){ return true; } else if(pRoot->element > element) return searchInBSTree(pRoot->pLeft,element,pNode); else return searchInBSTree(pRoot->pRight,element,pNode);}
4、二叉搜尋樹的插入
首先尋找二叉樹是是否已經存在該元素,如果已經存在返回false;如果不存在,插入該結點,插入元素大於根節點,則插入右子樹,否則,插入左子樹中。
bool insertIntoBSTree(BSTNode **pRoot,int element){ if(NULL == pRoot) return false; if(NULL == *pRoot){ *pRoot = allocNode(element); return NULL==*pRoot?false:true; } BSTNode **pSrc = NULL; if(searchInBSTree(pRoot,element,pSrc)) return false; BSTNode *pNode = allocNode(element); if(element < *pSrc->element) *pSrc->pLeft = pNode; else *pSrc->pRight = pNode; return true;}
5、二叉搜尋樹的刪除
二叉搜尋樹的刪除分為三種情況:
(1) 刪除結點為葉子結點,直接刪除該結點,再修改其父結點的指標(注意分是根結點和不是根節點)。
(2) 刪除結點為單支結點(即只有左子樹或右子樹)。
(3) 刪除結點的左子樹和右子樹均不空。
bool deleteFromBSTree(BSTNode **pRoot,int element){ if(NULL == pRoot || NULL == *pRoot) return false; BSTNode **pSrc = NULL; BSTNode **pParent = NULL; if(searchInBSTree(*pRoot,element,pParent,pSrc)){ if(NULL == *pSrc->pLeft && NULL == *pSrc->pRight){ free(*pSrc); *pSrc = NULL; return true; } else if(NULL == *pSrc->pLeft){ if(*pSrc == *pParent->pLeft) *pParent->pLeft = *pSrc->pRight; else if(*pSrc == *pParent->pRight) *pParent->pRight = *pSrc->pRight; free(*pSrc); return true; } else if(NULL == *pSrc->pRight){ if(*pSrc == *pParent->pLeft) *pParent->pLeft = *pSrc->pLeft; else if(*pSrc == *pParent->pRight) *pParent->pRight = *pSrc->pLeft; free(*pSrc); return true; } else{ BSTNode *pNode = *pSrc; BSTNode *pChild = *pSrc->pLeft; while(pChild->pRight){ pNode = pChild; pChild = pChild->pRight; } if(pNode == *pSrc) pNode->pLeft = pChild->pLeft; else pNode->pRight = pChild->pLeft; if(*pSrc == *pParent->pLeft) *pParent->pLeft = pChild; else *pParent->pRight = pChild; pChild->pLeft = *pSrc->pLeft; pChild->pRight = *pSrc->pRight; return true; } } return false;}
6、二叉搜尋樹的前序中序後序遍曆
/* preOrder to traverse the binarySearchTree.*/void preOrderBinarySearchTree(const BSTNode *pRoot){ if(NULL == pRoot) return ; printf("%d ",pRoot->element); preOrderBinarySearchTree(pRoot->pLeft); preOrderBinarySearchTree(pRoot->pRight);}/* inOrder to traverse the binarySearchTree.*/void inOrderBinarySearchTree(const BSTNode *pRoot){ if(NULL == pRoot) return ; inOrderBinarySearchTree(pRoot->pLeft); printf("%d ",pRoot->element); inOrderBinarySearchTree(pRoot->pRight);}/* posOrder to traverse the binarySearchTree.*/void posOrderBinarySearchTree(const BSTNode *pRoot){ if(NULL == pRoot) return ; posOrderBinarySearchTree(pRoot->pLeft); posOrderBinarySearchTree(pRoot->pRight); printf("%d ",pRoot->element);}
7、釋放結點
void freeBinarySearchTree(BSTNode *pRoot){ if(NULL == pRoot) return ; freeBinarySearchTree(pRoot->pLeft); freeBinarySearchTree(pRoot->pRight); free(pRoot);}
完整代碼詳見:https://github.com/whc2uestc/DataStructure-Algorithm/tree/master/tree
typedef struct binSrcTreeNode{ int element; struct binSrcTreeNode *pLeft; struct binSrcTreeNode *pRight;}BSTNode;
資料結構與演算法之二叉搜尋樹