在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(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; }