c語(yǔ)言實(shí)現(xiàn)二叉查找樹(shù)實(shí)例方法
以下為算法詳細(xì)流程及其實(shí)現(xiàn)。由于算法都用偽代碼給出,就免了一些文字描述。
/*******************************************
=================JJ日記=====================
作者: JJDiaries(阿呆)
郵箱:JJDiaries@gmail.com
日期: 2013-11-13
============================================
二叉查找樹(shù),支持的操作包括:SERACH、MINIMUM、
MAXIMUM、PREDECESSOR、SUCCESSOR、INSERT、DELETE。
定理:對(duì)于一個(gè)高度為h的二叉查找樹(shù),操作SERACH、MINIMUM、
MAXIMUM、PREDECESSOR、SUCCESSOR的運(yùn)行時(shí)間均為O(h)
*******************************************/
/*================JJ日記=====================
作者: JJDiaries(阿呆)
郵箱:JJDiaries@gmail.com
日期: 2013-11-13
============================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORDLEN 16
//定義一個(gè)節(jié)點(diǎn),除了存放key值外,還包含了一個(gè)data字符數(shù)組用于存放一個(gè)單詞
struct node{
int key;
char data[WORDLEN];
struct node *parent;
struct node *left;
struct node *right;
};
typedef struct node * tree;
/*============================================
樹(shù)的中序遍歷
INORDER_TREE_WALK(x)
if x!=NIL
then INORDER_TREE_WALK(left[x])
print key[x]
INORDER_TREE_WALK(left[x])
============================================*/
void inorder_tree_walk(tree T)
{
if(T!=NULL){
inorder_tree_walk(T->left);
printf("key:%d words:%s\n",T->key,T->data);
inorder_tree_walk(T->right);
}
}
/*============================================
樹(shù)的搜索,返回含有關(guān)鍵字k的結(jié)點(diǎn)
TREE_SEARCH(x,k) //遞歸版本
if x=NIL or k =key[x]
then return x
if k<key[x]
then return TREE_SEARCH(left[x],k)
else return TREE_SEARCH(right[x],k)
TREE_SEARCH(x,k) //非遞歸版本
while x!=NIL and k!= key[x]
do if k<key[x]
then x <—— left[x]
else x <—— right[x]
return x
============================================*/
//遞歸版本
struct node* tree_search(tree T,int k)
{
if(T==NULL || k == T->key)
return T;
if(k < T->key)
return tree_search(T->left,k);
else
return tree_search(T->right,k);
}
//非遞歸版本
struct node* tree_search1(tree T,int k)
{
while(T!=NULL && T->key!=k)
if(k < T->key)
T=T->left;
else
T=T->right;
return T;
}
/*============================================
返回key值最小的結(jié)點(diǎn)
TREE_MINIMUM(x)
while left[x]!=NIL
do x <—— left[x]
return x
============================================*/
struct node* tree_minimum(tree T)
{
while(T->left != NULL)
T=T->left;
return T;
}
/*============================================
返回key值最大的結(jié)點(diǎn)
TREE_MAXMUM(x)
while right[x]!=NIL
do x <—— right[x]
return x
============================================*/
struct node* tree_maxmum(tree T)
{
while(T->right != NULL)
T=T->right;
return T;
}
/*============================================
中序遍歷下,返回某一結(jié)點(diǎn)的后繼結(jié)點(diǎn)
1)如果結(jié)點(diǎn)x有右子結(jié)點(diǎn),則其后繼結(jié)點(diǎn)為右子樹(shù)中最小結(jié)點(diǎn)。
2)如果結(jié)點(diǎn)x沒(méi)有右子樹(shù),且x有一個(gè)后繼y,則y是x的最低祖先結(jié)點(diǎn)
且y的左兒子也是x的祖先。
TREE_SUCCESSOR(x)
if right[x] != NIL
return TREE_MINIMUM(right[x])
y=p[x]
while y!=NIL and x=right[y] //如果x=left[y],那么x的后繼就是y,跳出while循環(huán),直接返回y即可
do x <—— y
y <—— p[y]
return y
============================================*/
struct node * tree_successor(struct node *T)
{
if(T->right!=NULL)
return tree_minimum(T->right);
struct node *y=T->parent;
while(y!=NULL && T == y->right){
T=y;
y=y->parent;
}
return y;
}
/*===========================================
插入操作
思路:從根節(jié)點(diǎn)一路往下尋找插入位置,用指針x跟蹤這條尋找路徑,并用指針y指向x的父結(jié)點(diǎn)
TREE_INSERT(T,z)
y=NIL
x=root[T]
while x!= NIL //直到x為空,這個(gè)空位置即為需要插入的位置
do y<—— x
if key[z]<key[x]
then x <—— left[x]
else x <—— right[x]
p[z]=y
if y=NIL
then root[T]=z //樹(shù)T為空時(shí)的情況
else if key[z] < key[y]
then left[y]=z //小于y的插在左邊,大于的插在右邊
else right[y]=z
============================================*/
void tree_insert(tree *PT,struct node *z)
{
if(*PT==NULL){//樹(shù)為空,則將z作為根結(jié)點(diǎn)返回
*PT=z;
return;
}
struct node *y=NULL;
struct node *x=*PT;
while(x!=NULL){
y=x;
if(z->key < x->key)
x=x->left;
else
x=x->right;
}
z->parent=y;
if(z->key < y->key)
y->left=z;
else
y->right=z;
}
/*===============================================
刪除操作
刪除操作分為三類(lèi)情況:
1)若要?jiǎng)h除的節(jié)點(diǎn)z沒(méi)有子女,則只需修改z的父節(jié)點(diǎn)的該子女為NIL即可
2)若要?jiǎng)h除的節(jié)點(diǎn)z只有一個(gè)子女,則只需將z的這個(gè)子女與z的父節(jié)點(diǎn)連接起來(lái)即可
3)若要?jiǎng)h除的節(jié)點(diǎn)z有兩個(gè)子女,則需要先刪除z的后繼y,再用y的內(nèi)容替換z的內(nèi)容。
TREE_DELETE(T,z)
if left[z]=NIL || right[z]=NIL //把要?jiǎng)h除的節(jié)點(diǎn)先保存在y中
then y <—— z
else y <—— TREE_SUCCESSOR(z)
if left[y]!=NIL //將y的非空子女存放在x中
then X <—— left[y]
else x <—— right[y]
if x!=NIL
then p[x]=p[y] //將要?jiǎng)h除節(jié)點(diǎn)的子女連接到要?jiǎng)h除節(jié)點(diǎn)的父節(jié)點(diǎn)上
if p[y]=NIL //如果要?jiǎng)h除的節(jié)點(diǎn)為根節(jié)點(diǎn)
then root[T] <—— x
else if y=left[p[y]]//
then left[p[y]] <—— x
else right[p[y]] <—— x
if y!=z //第三種情況,需要用y的內(nèi)容替換z的內(nèi)容
then key[z] <—— key[y]
copy y's other data to z
return y
==============================================*/
struct node * tree_delete(tree *PT,struct node *z)
{
struct node *delnode,*sonnode;
if(z->left==NULL || z->right == NULL)//有一個(gè)子女或無(wú)子女,則要?jiǎng)h除的結(jié)點(diǎn)結(jié)尾z本身
delnode=z;
else //有兩個(gè)子女,則要?jiǎng)h除的結(jié)點(diǎn)為z的后繼結(jié)點(diǎn)
delnode=tree_successor(z);
if(delnode->left!=NULL)
sonnode=delnode->left;
else
sonnode=delnode->right;
if(sonnode!=NULL)
sonnode->parent=delnode->parent;
if(delnode->parent==NULL)
*PT=sonnode;
else if(delnode->parent->left==delnode)
delnode->parent->left=sonnode;
else
delnode->parent->right=sonnode;
if(delnode!=z){
z->key=delnode->key;
strcpy(z->data,delnode->data);
}
return delnode;
}
//初始化一棵樹(shù)
tree init_tree(int key)
{
struct node * t;
t=(tree)malloc(sizeof(struct node));
if(t==NULL)
return NULL;
t->key=key;
t->parent=t->left=t->right=NULL;
return t;
}
//釋放資源
void fini_tree(tree T)
{
if(T!=NULL){
fini_tree(T->left);
fini_tree(T->right);
printf("free node(%d,%s) now\n",T->key,T->data);
free(T);
}
}
//測(cè)試程序
int main()
{
tree myTree=init_tree(256);
if(myTree==NULL)
return 1;
strcpy(myTree->data,"JJDiaries");
struct record{
int key;
char word[WORDLEN];
};
struct record records[]={ {2,"Viidiot"},
{4,"linux-code"},
{123,"google"},
{345,"baidu"},
{543,"nsfocus"}
};
int i;
struct node *tmp;
for(i=0;i<5;++i){
tmp=(tree)malloc(sizeof(struct node));
if(tmp==NULL)
continue;
tmp->key=records[i].key;
strcpy(tmp->data,records[i].word);
tmp->left=tmp->right=tmp->parent=NULL;
tree_insert(&myTree,tmp);
}
inorder_tree_walk(myTree);
struct node *del;
del=tree_delete(&myTree,tree_search(myTree,345));
printf("Delete node(%d,%s)\n",del->key,del->data);
free(del);
inorder_tree_walk(myTree);
fini_tree(myTree);
}
程序運(yùn)行結(jié)果:
jjdiaries@ubuntu>./search_tree
key:2 words:Viidiot
key:4 words:linux-code
key:123 words:google
key:256 words:JJDiaries
key:345 words:baidu
key:543 words:nsfocus
Delete node(345,baidu)
key:2 words:Viidiot
key:4 words:linux-code
key:123 words:google
key:256 words:JJDiaries
key:543 words:nsfocus
free node(123,google) now
free node(4,linux-code) now
free node(2,Viidiot) now
free node(543,nsfocus) now
free node(256,JJDiaries) now
- 使用C語(yǔ)言構(gòu)建基本的二叉樹(shù)數(shù)據(jù)結(jié)構(gòu)
- 用C語(yǔ)言判斷一個(gè)二叉樹(shù)是否為另一個(gè)的子結(jié)構(gòu)
- 使用C語(yǔ)言求二叉樹(shù)結(jié)點(diǎn)的最低公共祖先的方法
- C語(yǔ)言實(shí)現(xiàn)二叉樹(shù)遍歷的迭代算法
- C語(yǔ)言實(shí)現(xiàn)輸入一顆二元查找樹(shù)并將該樹(shù)轉(zhuǎn)換為它的鏡像
- C語(yǔ)言實(shí)現(xiàn)找出二叉樹(shù)中某個(gè)值的所有路徑的方法
- C語(yǔ)言實(shí)現(xiàn)計(jì)算樹(shù)的深度的方法
- C語(yǔ)言二叉樹(shù)的非遞歸遍歷實(shí)例分析
- c語(yǔ)言版本二叉樹(shù)基本操作示例(先序 遞歸 非遞歸)
- 一波C語(yǔ)言二元查找樹(shù)算法題目解答實(shí)例匯總
相關(guān)文章
C語(yǔ)言putenv()函數(shù)和getenv()函數(shù)的使用詳解
這篇文章主要介紹了C語(yǔ)言putenv()函數(shù)和getenv()函數(shù)的使用詳解,用來(lái)進(jìn)行環(huán)境變量的相關(guān)操作,需要的朋友可以參考下2015-09-09C語(yǔ)言超詳細(xì)講解字符串函數(shù)和內(nèi)存函數(shù)
這篇文章主要介紹一些c語(yǔ)言中常用字符串函數(shù)和內(nèi)存函數(shù)的使用,字符串函數(shù)(String?processing?function)也叫字符串處理函數(shù),指的是編程語(yǔ)言中用來(lái)進(jìn)行字符串處理的函數(shù)2022-05-05Mac下使用Eclipse編譯C/C++文件出現(xiàn) launch failed, binary not found 解決方
這篇文章主要介紹了Mac下使用Eclipse編譯C/C++文件出現(xiàn) launch failed, binary not found 解決方案,需要的朋友可以參考下2014-10-10C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)字符串分割的實(shí)例
這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)字符串分割的實(shí)例的相關(guān)資料,希望通過(guò)本文能幫助到大家實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下2017-10-10C++ for循環(huán)與nullptr的小知識(shí)點(diǎn)分享
這篇文章主要是來(lái)和大家介紹一些C++中的小知識(shí)點(diǎn),本文分享的是for循環(huán)與nullptr,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-05-05