平衡二叉樹之二叉排序樹

最近寫了點題目,用到平衡二叉樹,以後看過,但是現在完全不記得了......可能以後去面試也要寫到平衡二叉樹的....重新學習一下.....

平衡二叉樹是在二叉排序樹的基礎上成立的,所以先來弄一下二叉排序樹。


二叉排序樹或者是一棵空樹,或者是具有下列性質的二叉樹:(其實就是子節點比結點大或等於的就放結點右邊,小的放左邊)
(1)若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
(2)若右子樹不空,則右子樹上所有結點的值均大於或等於它的根結點的值;
(3)左、右子樹也分別爲二叉排序樹;
(4)沒有鍵值相等的節點。

圖示爲一個二叉排序樹




#include "stdio.h"
#include "stdlib.h"


//定義二叉排序樹的結構
typedef struct BNODE 
{
int data;//結點的數據
struct BNODE *lchild, *rchild;//左子樹指針和右子樹指針


}BNODE,*BTree;






//二叉排序樹的查找
bool FindTree(BTree T, int key, BTree f, BTree *p)//指針f指向T的父結點,如果查找成功,p指向該查找的結點,返回true。查找失敗p就指向查找路徑上時所訪問的最後一個結點,返回false
{
if (!T)//查找不成功
{
*p = f;
return false;
}
else if (T->data == key)//查找成功
{
*p = T;
return true;
}
else if (T->data>key)
{
FindTree(T->lchild, key, T, p);//大於就在左子樹繼續查找
}
else
{
FindTree(T->rchild, key, T, p);//小於就在右子樹繼續查找
}

}






//二叉排序樹的插入操作
bool InsetTree(BTree T, int key)//當二叉排序樹T中不存在關鍵字等於key的數據時,插入key並返回true,否則返回false
{
BTree s, p;
if (!FindTree(T, key, NULL, &p))//查找不成功,插入
{
s = (BTree)malloc(sizeof(BNODE));//創建結點s
s->data = key;
s->lchild = s->rchild = NULL;
if (!p)
T = s;
else if (p->data > key)
p->lchild = s;//插入s爲左結點
else
{
p->rchild = s;//插入s爲右結點
}
return true;


}
return false;
}




//創建一個二叉排序樹,這樣就可以創建出上圖所示的那個二叉排序樹了,各位自己抽象地想象一下
void main()
{
int i;
int a[9] = { 8, 3, 1, 6, 4, 7, 10, 14, 13 };
BTree T = NULL;
for (i = 0; i < 9;i++)
{
InsetTree(T, a[i]);
}
}





//從查找到創建二叉排序樹挺簡單的,但請神容易送神難,二叉排序樹的刪除操作就難了
//因爲根據二叉排序樹的結構特點,小的插左邊,大的插右邊,隨便刪除一個數據都會導致結構混亂
//解決的方法就是尋找被刪除結點數據的前驅或後繼來繼承被刪除結點(就是和被刪除結點數據的最接近的那兩個結點數據,一大一小)
//最近的結點說我繼承了遺產,哇哈哈哈哈



//好了,廢話不多說,下面是二叉排序樹的刪除操作
//如果二叉排序樹中存在和key相等的結點,就刪除該結點並返回true,否則返回false

bool DeleteTree(BTree *T, int key)
{
if (!*T)//不存在和key相等的數據
{
return false;
}
else
{
if ((*T)->data == key)//找到和key相等的數據了,刪除掉
return Delete(T);
else if ((*T)->data > key)
return DeleteTree(&(*T)->lchild, key);
else
{
return DeleteTree(&(*T)->rchild, key);
}
}


}


//刪除操作的具體代碼
//刪除結點p,並重接它的左子樹或者右子樹

bool Delete(BTree *p)
{
BTree q, s;
if ((*p)->rchild == NULL)//右子樹空就只需要重接它的左子樹
{
q = *p; *p = (*p)->lchild; free(q);
}
else if ((*p)->lchild == NULL)//左子樹空就只需要重接它的右子樹
{
q = *p; *p = (*p)->rchild; free(q);
}
else//左子樹和右子樹都不空的情況
{
q = *p; s = (*p)->lchild;
while (s->rchild)//轉左,然後向右到盡頭(找待刪除結點的前驅)
{
q = s; s = s->rchild;
}
(*p)->data = s->data;//s指向被刪除結點的直接前驅
if (q != *p)
{
q->rchild = s->lchild;//重接q的右子樹
}
else
q->lchild = s->lchild;//重接q的左子樹
free(s);
}
return true;
}




//後面的刪除代碼可能有點理解不了...但是時間有限...有空我在詳細修改一下...見諒

發佈了29 篇原創文章 · 獲贊 9 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章