利用C语言实现二叉搜索树的遍历、查找、插入、删除
IDE:codebloks,編譯器:gcc5.1.0
二叉搜索樹和我們通常的二叉樹還是有一定的區別,顧名思義,一顆二叉搜索樹以一顆二叉樹來組織,其中每一個結點就是一個對象。除了key(關鍵字)和衛星數據外,每個節點還包括left(左孩子指針)、right(右孩子指針)和p。如果孩子結點不存在則為NULL。
二叉搜索樹的性質如下:
設x是二叉搜索樹中的一個結點。如果y是x的左子樹中的一個結點,那么y.key≤x.key。如果y是x右子樹中的一個結點,那么y.key≥x.key。圖a和b正好說明了這一點。
二叉搜索樹的遍歷有三種,分別為先序遍歷(perorder tree walk)、中序遍歷(inorder tree walk)、后續遍歷(postorder tree walk)。
1.首選定義二叉搜索樹結點的數據結構,為了簡單期間,只定義了關鍵字,左孩子和右孩子指針本例子中的二叉搜索樹如圖c所示:
2.下面分別是三種遍歷的C語言實現。唯一不同的地方是輸出關鍵字的位置不void PreTraverseBSTree(pBstNode pBST)
void PreTraverseBSTree(struct BSTNode *pBST) {if(NULL != pBST){printf("數據為:%d,父節點地址為:%p\n",pBST ->data,pBST ->pParent);if(NULL != pBST ->pLchild )PreTraverseBSTree(pBST ->pLchild);if(NULL != pBST ->pRchild)PreTraverseBSTree(pBST ->pRchild);} }void InTraverseBSTree(struct BSTNode *pBST) {if(NULL != pBST){if(NULL != pBST ->pLchild )PreTraverseBSTree(pBST ->pLchild);printf("數據為:%d,父節點地址為:%p\n",pBST ->data,pBST ->pParent);if(NULL != pBST ->pRchild)PreTraverseBSTree(pBST ->pRchild);} }void PostTraverseBSTree(struct BSTNode *pBST) {if(NULL != pBST){if(NULL != pBST ->pLchild )PreTraverseBSTree(pBST ->pLchild);if(NULL != pBST ->pRchild)PreTraverseBSTree(pBST ->pRchild);printf("數據為:%d,父節點地址為:%p\n",pBST ->data,pBST ->pParent);} }3.下面是查找的C語言實現。第一個版本是自己實現的,在寫的過程中,想到了是不是可以去掉return,去掉return編譯器報警,經過一番查找資料和思考,發現有沒有return不會影響結果,報警的原因是SearchBSTree()的返回值類型是pBstNode,如果去掉return就沒有返回值,類型不匹配就會報警。版本1沒有版本2效率高,版本2沒有版本3效率高,版本2和版本3參考自《算法導論》。版本3采用了while循環展開遞歸,用一種迭代方式重寫這個過程。對于大多數計算機,迭代版本的效率要高很多。
//查找成功返回該結點的地址,失敗返回NULL struct BSTNode *SearchBSTree(struct BSTNode *pBST,int key) //版本1 {if(NULL == pBST)return NULL;else if(key < pBST ->data)return SearchBSTree(pBST ->pLchild,key);else if(key > pBST ->data)return SearchBSTree(pBST ->pRchild,key);else return pBST; }struct BSTNode *SearchBSTree(struct BSTNode *pBST,int key) //版本2 {if(NULL == pBST || key == pBST ->data)return pBST;else if(key < pBST ->data)return SearchBSTree(pBST ->pLchild,key);else return SearchBSTree(pBST ->pRchild,key); }struct BSTNode *SearchBSTree(struct BSTNode *pBST,int key) //版本3 {while(NULL != pBST && key != pBST ->data){if(key < pBST ->data)pBST = pBST ->pLchild;else pBST = pBST ->pRchild;}return pBST; }4.在二叉搜索樹中尋找最大值和最小值。由二叉搜索樹的性質可知,我們總能在二叉搜索樹中找到一個元素,兩個擁有相同父結點的子結點中,左結子點的值肯定小于父節點,也小于右子結點,所以最小值總在二叉搜索樹的左子樹中,最大值總在右子樹中。實現的代碼如下:時間復雜度為O(h)。
struct BSTNode *SearchMinBSTree(struct BSTNode *pBST,int *pMinData)//查找二叉搜索樹中最小的值 {while(NULL != pBST ->pLchild){pBST = pBST ->pLchild;}*pMinData = pBST ->data;return pBST; } struct BSTNode *SearchMaxBSTree(struct BSTNode *pBST,int *pMaxData) //查找二叉搜索樹中最大的值 {while(NULL != pBST ->pRchild){pBST = pBST ->pRchild;}*pMaxData = pBST ->data;return pBST; }5.向二叉樹中插入一個元素
void InsertBSTree(struct BSTNode *pBST,int InsertVal) //插入元素 {struct BSTNode *pRoot = pBST;//記錄根節點地址struct BSTNode *pNew = (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pNew)exit(-1);pNew ->data = InsertVal;pNew ->pLchild = pNew ->pRchild = NULL;struct BSTNode *pTmp = NULL;while(NULL != pBST ){pTmp = pBST;if(pNew ->data < pBST ->data)pBST = pBST ->pLchild;elsepBST = pBST ->pRchild;}pNew->pParent = pTmp;if(NULL == pTmp) //當樹為空時,將插入節點的地址賦給根節點*pRoot = *pNew;else if(pNew ->data <= pTmp ->data)pTmp ->pLchild = pNew;elsepTmp ->pRchild = pNew; }6.刪除二叉樹中的元素
void DeleteBSTree(struct BSTNode *pBST,int DeleteVal) {struct BSTNode *pTem = SearchBSTree(pBST,DeleteVal);if(pTem == NULL){printf("沒有找到要刪除的元素!\n");exit(-1);}if(NULL == pTem ->pLchild && NULL == pTem ->pRchild) //刪除節點無左右孩子{if(pTem == pTem ->pParent ->pLchild) //刪除節點是其父節點的左孩子{pTem ->pParent ->pLchild = NULL;}else //刪除節點是其父節點的右孩子{pTem ->pParent ->pRchild =NULL;}free(pTem);pTem = NULL;}else if(NULL == pTem ->pLchild) //刪除節點無左孩子{if(pTem == pTem ->pParent ->pLchild) //刪除節點為其父節點的左孩子{pTem ->pParent ->pLchild = pTem ->pRchild;pTem ->pRchild ->pParent =pTem ->pParent;}else //刪除節點為其父節點的右孩子{pTem ->pParent ->pRchild = pTem ->pRchild;pTem ->pRchild ->pParent =pTem ->pParent;}free(pTem);pTem = NULL;}else if(NULL == pTem ->pRchild) //刪除節點無右孩子{if(pTem == pTem ->pParent->pLchild) //刪除節點為其父節點的左孩子{pTem ->pParent ->pLchild = pTem ->pLchild;pTem ->pLchild ->pParent = pTem ->pParent;}else //刪除節點為其父節點的右孩子{pTem ->pParent ->pRchild = pTem ->pLchild;pTem ->pLchild ->pParent = pTem ->pParent;}free(pTem);pTem = NULL;}else //刪除節點有左右孩子,用刪除節點左字樹中的最大值或者右子樹中最小值來代替刪除節點//本例中用右子樹中最小值來代替{struct BSTNode *pTial = pTem ->pRchild;while(NULL != pTial ->pLchild) //查找右子樹中的最小值{pTial = pTial ->pLchild;}if(pTem == pTial ->pParent) //右子樹中的最小值的父節點是刪除節點{if(pTem == pTem ->pParent ->pLchild) //刪除節點為其父節點的左孩子{pTem ->pParent ->pLchild = pTial;pTial ->pLchild = pTem ->pLchild;pTem ->pLchild->pParent = pTial;}else{pTem ->pParent ->pRchild = pTial;pTial ->pLchild = pTem ->pLchild;pTem ->pLchild->pParent = pTial;}free(pTem);pTem = NULL;}else{pTial ->pRchild ->pParent = pTial ->pParent;pTial ->pParent ->pLchild = pTial ->pRchild;pTial ->pParent ->pParent = pTial;pTial ->pRchild = pTial ->pParent;pTial ->pLchild = pTem ->pLchild;pTem ->pLchild ->pParent = pTial;if(pTem == pTem ->pParent ->pLchild){pTem ->pParent ->pLchild = pTial;}elsepTem ->pParent ->pRchild = pTial;free(pTem);pTem = NULL;}} }7.創建一顆二叉搜索樹
struct BSTNode *CreateBSTree(void) {struct BSTNode * pA = (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pA)exit(-1);struct BSTNode * pB= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pB)exit(-1);struct BSTNode * pC= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pC)exit(-1);struct BSTNode * pD= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pD)exit(-1);struct BSTNode * pE= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pE)exit(-1);struct BSTNode * pF= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pF)exit(-1);struct BSTNode * pG= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pG)exit(-1);struct BSTNode * pH= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pH)exit(-1);struct BSTNode * pI= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pI)exit(-1);struct BSTNode * pJ= (struct BSTNode *)malloc(sizeof(struct BSTNode));if(NULL == pJ)exit(-1);pA ->data = 4;pB ->data = 2;pC ->data = 7;pD ->data = 3;pE ->data = 6;pF ->data = 13;pG ->data = 5;pH ->data = 10;pI ->data = 14;pJ ->data = 11;pA ->pParent = NULL;pA ->pLchild = pB;pA ->pRchild = pC;pB ->pParent = pA;pB ->pLchild = NULL;pB ->pRchild = pD;pD ->pParent = pB;pD ->pLchild = pD ->pRchild = NULL;pC ->pParent = pA;pC ->pLchild = pE;pC ->pRchild = pF;pE ->pParent = pC;pE ->pLchild = pG;pE ->pRchild = NULL;pF ->pParent = pC;pF ->pRchild = pI;pF ->pLchild =pH;pG ->pParent = pE;pG ->pLchild = pG ->pRchild = NULL;pH ->pParent = pF;pH ->pLchild = NULL;pH ->pRchild = pJ;pI ->pParent = pF;pI ->pLchild = pI ->pRchild = NULL;pJ ->pParent = pH;pJ ->pLchild = pJ ->pRchild =NULL;return pA; }8.主函數
int main() {int MinData,MaxData;struct BSTNode *pRoot;pRoot=CreateBSTree();//printf("先序遍歷:\n");//PreTraverseBSTree(pRoot);printf("\n中序遍歷:\n");InTraverseBSTree(pRoot);//printf("\n后續遍歷:\n");//PostTraverseBSTree(pRoot);printf("\n查找的元素為: key = 5");struct BSTNode *pKeyNode = SearchBSTree(pRoot,5);if(NULL == pKeyNode)printf("查找失敗!\n");elseprintf("\n查找成功,結點地址為:%p!",pKeyNode);struct BSTNode *pMinData = SearchMinBSTree(pRoot,&MinData);printf("\n最小值為:%d,其結點地址為:%p",MinData,pMinData);struct BSTNode *pMaxDate = SearchMaxBSTree(pRoot,&MaxData);printf("\n最大值為:%d,其結點地址為:%p",MaxData,pMaxDate);printf("\n插入的元素為: data = 10");InsertBSTree(pRoot,1); //插入元素printf("\n中序遍歷:\n");InTraverseBSTree(pRoot);DeleteBSTree(pRoot,4);printf("\n中序遍歷:\n");InTraverseBSTree(pRoot);return 0; }9.運行結果
中序遍歷:
數據為:2,父節點地址為:00e11700
數據為:3,父節點地址為:00e11718
數據為:4,父節點地址為:00000000
數據為:7,父節點地址為:00e11700
數據為:6,父節點地址為:00e11730
數據為:5,父節點地址為:00e11760
數據為:13,父節點地址為:00e11730
數據為:10,父節點地址為:00e11778
數據為:11,父節點地址為:00e117a8
數據為:14,父節點地址為:00e11778
查找的元素為: key = 5
查找成功,結點地址為:00e11790!
最小值為:2,其結點地址為:00e11718
最大值為:14,其結點地址為:00e117c0
插入的元素為: data = 10
中序遍歷:
數據為:2,父節點地址為:00e11700
數據為:1,父節點地址為:00e11718
數據為:3,父節點地址為:00e11718
數據為:4,父節點地址為:00000000
數據為:7,父節點地址為:00e11700
數據為:6,父節點地址為:00e11730
數據為:5,父節點地址為:00e11760
數據為:13,父節點地址為:00e11730
數據為:10,父節點地址為:00e11778
數據為:11,父節點地址為:00e117a8
數據為:14,父節點地址為:00e11778
中序遍歷:
數據為:2,父節點地址為:00e11700
數據為:1,父節點地址為:00e11718
數據為:3,父節點地址為:00e11718
數據為:4,父節點地址為:00000000
數據為:10,父節點地址為:00e11778
數據為:6,父節點地址為:00e117a8
數據為:5,父節點地址為:00e11760
數據為:13,父節點地址為:00e117a8
數據為:11,父節點地址為:00e11778
數據為:14,父節點地址為:00e11778
總結
以上是生活随笔為你收集整理的利用C语言实现二叉搜索树的遍历、查找、插入、删除的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Arduino-超声波测距仪-实现近距离
- 下一篇: Vscode所见即所得的Markdown