在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)
和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
二叉查找树的C 语言实现如下:
分别有三部分:main.c Head.h fun.c
头文件Head.h
#ifndef HEAD_H_
#define HEAD_H_
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct TreeNode
{
ElementType Element;
struct TreeNode *Left;
struct TreeNode *Right;
}*Position,*SearchTree;
SearchTree MakeEmpty(SearchTree T);
Position Find(ElementType x,SearchTree T);
Position FindMin(SearchTree T);
Position FindMax(SearchTree T);
SearchTree Insert(ElementType x,SearchTree T);
SearchTree Delete(ElementType x,SearchTree T);
ElementType Retrieve(Position P);
void PrintTree(SearchTree T);
#endif /* HEAD_H_ */
功能函数fun.c
#include"Head.h"
/*
* 此操作主要用于初始化
*/
SearchTree MakeEmpty(SearchTree T)
{
if(T!=NULL)
{
MakeEmpty(T->Left);
MakeEmpty(T->Right);
free(T);
}
return NULL;
}
/*
* Find 返回指向树T中具有关键字 x 的节点的指针,不存在则返回NULL。
* 注意这里两个递归都是尾递归,所使用的栈空间 只有 O(log N)
*/
Position Find(ElementType x,SearchTree T)
{
if(T == NULL)
return NULL;
if(x < T->Element)
return Find(x,T->Left);
else if(x > T->Element)
return Find(x,T->Right);
else
return T;
}
/*
* FindMin 和 FindMax 分别返回树中最小元和最大元
* FindMin 采用 递归的方式
* FindMax 采用 非递归方式
*/
Position FindMin(SearchTree T)
{
if(T == NULL)
return NULL;
if(T->Left == NULL)
return T;
else
return FindMin(T->Left);
}
Position FindMax(SearchTree T)
{
if(T != NULL)
while(T->Right != NULL)
T=T->Right;
return T;
}
/*
* Insert 向树中插入元素,树中递归的向左右子树中插入
*/
SearchTree Insert(ElementType x,SearchTree T)
{
if(T == NULL) //当树为空时
{
// 创建节点
T = (SearchTree)malloc(sizeof(struct TreeNode));
if(T == NULL)
{
puts("out of space \n");
exit(-1);
}
else
{
T->Element=x;
T->Left=T->Right=NULL;
}
}
else if(x < T->Element) //插入左子树
{
T->Left=Insert(x,T->Left);
}
else //插入右子树
{
T->Right=Insert(x,T->Right);
}
//如果元素已经存在节点中,什么也不做
return T;
}
/*
* 删除树中某一个元素,分为以下情况
* 1.树为空,返回NULL
* 2.要删除的元素在左子树中,递归的在左子树中删除
* 3.同理,要删除的元素在右子树中,递归的在右子树中删除
* 4.找到要删除的元素,且节点只有一个孩子,或者没有孩子,是叶子
* 5.找到要删除的元素,而且节点有两个孩子,此时最为复杂,
* (这种情况时,此种方法效率不高,因为要沿着树进行两次搜索)
*/
SearchTree Delete(ElementType x,SearchTree T)
{
Position TmpCell;
if(T == NULL)
puts("Element not found \n");
else if(x < T->Element) // x 在 左子树中
T->Left=Delete(x,T->Left);
else if(x > T->Element) // x 在 右子树中
T->Right=Delete(x,T->Right);
// 找到要删除的元素,而且节点有两个孩子
else if(T->Left && T->Right)
{
// 找到节点 T 的右子树中最小的节点,但这个节点元素是大于 T 的
TmpCell=FindMin(T->Right);
//将右子树中最小的但大于T的元素取代T,
T->Element=TmpCell->Element;
/*
* 递归的删除 T 的右子树中最小的元素,即刚取代T的那个节点,
* 第二次删除较容易,因为 T 的右子树中最小的节点元素没有 左孩子
*/
T->Right=Delete(T->Element,T->Right);
}
// 找到要删除的元素,但是节点只有一个孩子,或者没有孩子
else
{
TmpCell=T;
//如果节点 T->Left 的左孩子为空,则 T->Left 的父节点 绕过 该节点后删除
if(T->Left == NULL)
T=T->Right;
//如果节点 T->Right 的右孩子为空,则 T->Right 的父节点 绕过 该节点后删除
else if(T->Right == NULL)
T=T->Left;
free(TmpCell);
}
return T;
}
/*
* 返回位置 p 的元素
*/
ElementType Retrieve(Position P)
{
return P->Element;
}
/*
* 中序遍历 ,先是遍历左子树,在是当前节点,最后是右子树
* 总的运行时间为 O(N)
*/
void PrintTree(SearchTree T)
{
if(T != NULL)
{
PrintTree(T->Left);
printf("%d \n",T->Element);
PrintTree(T->Right);
}
}
主函数main.c
#include"Head.h"
int main(void) {
SearchTree T;
Position P;
int i;
int j = 0;
T = MakeEmpty( NULL );
for( i = 0; i < 50; i++, j = ( j + 7 ) % 50 )
T = Insert( j, T );
PrintTree(T);
for( i = 0; i < 50; i++ )
if( ( P = Find( i, T ) ) == NULL || Retrieve( P ) != i )
printf( "Error at %d\n", i );
for( i = 0; i < 50; i += 2 )
T = Delete( i, T );
puts("after delete:\n");
PrintTree(T);
for( i = 1; i < 50; i += 2 )
if( ( P = Find( i, T ) ) == NULL || Retrieve( P ) != i )
printf( "Error at %d\n", i );
for( i = 0; i < 50; i += 2 )
if( ( P = Find( i, T ) ) != NULL )
printf( "Error at %d\n", i );
printf( "Min is %d, Max is %d\n", Retrieve( FindMin( T ) ),
Retrieve( FindMax( T ) ) );
return EXIT_SUCCESS;
}