本文原始地址:C演算法學習筆記(2)-二叉尋找樹
尋找操作
若根結點的關鍵字值等於尋找的關鍵字,成功。
否則,若小於根結點的關鍵字值,遞迴查左子樹。
若大於根結點的關鍵字值,遞迴查右子樹。
若子樹為空白,尋找不成功。
/* //二叉樹尋找演算法 //T 二叉樹 //x 要尋找的值 */BiTree BSTSearch(BiTree T,int x){ BiTreeNode *p; if (T != NULL) { p = T; while (p != NULL) { if (p->data == x)//如果該結點就是我們想要的 { return p; }else if(x > p->data)//如果尋找的值是該結點右子樹 { p = p->rchild; }else//如果尋找的值是該結點左子樹 { p = p->lchild; } } } return NULL;}
插入操作
首先執行尋找演算法,找出被插結點的父親結點。
判斷被插結點是其父親結點的左、右兒子。將被插結點作為葉子結點插入。
若二叉樹為空白。則首先單獨產生根結點。
注意:新插入的結點總是葉子結點。
/* //二叉樹插入操作 //T 二叉樹 //x 要插入的值 */int BSTInsert(BiTree *T,int x){ BiTreeNode *p = NULL;//把x組裝成一個只有根結點的樹 BiTreeNode *cur = NULL;//紀錄當前遍曆的結點 BiTreeNode *parent = NULL;//紀錄上一次遍曆的結點,最後一個值為我們需要插入的結點位置 cur = *T; while (cur != NULL) { if (cur->data == x)//插入操作如果數值已存在,插入失敗 { return 0; } parent = cur;//將到該結點子樹遍曆,紀錄下該結點,該迴圈最終輸出值 if (x < cur->data)//到該結點左子樹繼續遍曆 { cur = cur->lchild; }else//到該結點右子樹繼續遍曆 { cur = cur->rchild; } } //申請記憶體空間 p = (BiTreeNode *)malloc(sizeof(BiTreeNode)); if (!p)//記憶體空間申請失敗,記憶體不夠用了,終止程式 { exit(-1); } //初始化p結點 p->data = x; p->lchild = NULL; p->rchild = NULL; if (!parent) { *T = p;//這本來就是棵空樹,p將會作為根結點 }else if(x < parent->data) { parent->lchild = p; }else { parent->rchild = p; } return 1;//插入成功}
刪除操作
1.若*p結點為葉子結點,即PL(左子樹)和PR(右子樹)均為空白樹。由於刪去葉子結點不破壞整棵樹的結構,則只需修改其雙親結點的指標即可。
2.若*p結點只有左子樹PL或右子樹PR,此時只要令PL或PR直接成為其雙親結點*f的左子樹(當*p是左子樹)或右子樹(當*p是右子樹)即可,作此修改也不破壞二叉排序樹的特性。
3.若*p結點的左子樹和右子樹均不空。在刪去*p之後,為保持其它元素之間的相對位置不變,可按中序遍曆保持有序進行調整,可以有兩種做法:
其一是令*p的左子樹為*f的左/右(依*p是*f的左子樹還是右子樹而定)子樹,*s為*p左子樹的最右下的結點,而*p的右子樹為*s的右子樹;
其二是令*p的直接前驅(或直接後繼)替代*p,然後再從二叉排序樹中刪去它的直接前驅(或直接後繼)-即讓*f的左子樹(如果有的話)成為*p左子樹的最左下結點(如果有的話),再讓*f成為*p的左右結點的父結點。
/* //刪除結點 //刪除的結點s //原則:保持二叉樹性質不變-根結點的值大於左子樹的值小於右子樹的值... */void DeleteNode(BiTree *s){ if (!s) return; BiTreeNode *q = NULL;//中間量,紀錄舊的的s結點資料 BiTreeNode *x = NULL; BiTreeNode *y = NULL; if(!(*s)->rchild)//如果右子樹不存在 { q = (*s); (*s) = (*s)->lchild; free(q); }else if(!(*s)->lchild)//如果左子樹不存在 { q = (*s); (*s) = (*s)->rchild; }else//如果左右都存在的話,令*p的直接前驅(或直接後繼)替代*p,然後再從二叉排序樹中刪去它的直接前驅(或直接後繼)-即讓*f的左子樹(如果有的話)成為*p左子樹的最左下結點(如果有的話),再讓*f成為*p的左右結點的父結點。 { x = (*s); y = (*s)->lchild; while (y->rchild)//尋找s的直接前驅結點,y為s的直接前驅結點,x為y的雙親結點 { x = y; y = y->lchild; } (*s)->data = y->data;//結點s被y取代 if (x != (*s))//如果結點s的左孩子結點不存在右子樹 { x->rchild = y->lchild;//使y的左子樹成為x的右子樹 }else { x->lchild = y->lchild; } free(y); }}/* //在二叉樹中尋找關鍵字為x的結點,並刪除,刪除成功返回1,否則返回0 //T 二叉樹 //x 關鍵字 */int BSTDelete(BiTree *T,int x){ if (!*T) return 0; if (x == (*T)->data) { DeleteNode(T); }else if (x < (*T)->data) { BSTDelete(&(*T)->lchild,x); }else { BSTDelete(&(*T)->rchild,x); } return 1;}
附:中序遍曆
//中序遍曆void InOrderTraverse(BiTree T){ if (T) { InOrderTraverse(T->lchild); printf("%4d",T->data); InOrderTraverse(T->rchild); }}
視頻地址:BST:二叉尋找樹
關於二叉尋找樹