“二叉查找树”学习

查找二叉树的定义:

image

存储结构和二叉树相同:

image

需要实现的方法:

image

代码:

tree.h

#ifndef _TREE_H
#define _TREE_H

typedef int ElemType;

typedef struct treenode
{
	ElemType data;
	struct treenode * left;
	struct treenode * right;
}TREE;



TREE *MakeEmptyTree();

TREE *InsertTreeNode(ElemType e,TREE *t);

TREE *FindTreeNode(ElemType e,TREE *t);

TREE *FindMax(TREE *t);

TREE *FindMin(TREE *t);

TREE *DeleteTreeNode(ElemType e,TREE *t);

void DeleteTree(TREE **t);

#endif

tree.c

#include<stdio.h>
#include<stdlib.h>
#include"tree.h"


TREE *MakeEmptyTree()
{
	return NULL;
}

TREE *InsertTreeNode(ElemType e,TREE *t)
{
	if(t == NULL)
	{
		t = (TREE *)malloc(sizeof(TREE));
		if(t == NULL) return NULL;
		t->data = e;
		t->left = t->right = NULL;
	}else if(e < t->data)
		t->left = InsertTreeNode(e,t->left);
	else
		t->right = InsertTreeNode(e,t->right);
	return t;
}

TREE *FindTreeNode(ElemType e,TREE *t)
{
	if(t == NULL) return NULL;
	if(t->data == e)
		return t;
	else if(t->data < e)
		return FindTreeNode(e,t->right);
	else 
		return FindTreeNode(e,t->left);
}

TREE *FindMax(TREE *t)
{
	if(t == NULL)
		return NULL;
	if(t->right == NULL)
		return t;
	return FindMax(t->right);
}

TREE *FindMin(TREE *t)
{
	if(t == NULL)return NULL;
	if(t->left == NULL)
		return t;
	return FindMin(t->left);
}

TREE *DeleteTreeNode(ElemType e,TREE *t)
{
	TREE *p = NULL;
	if(t == NULL)return NULL;
	if(t->data > e)//数据比根小
		t->left = DeleteTreeNode(e,t->left);//去左子树删
	else if(t->data < e)
		t->right = DeleteTreeNode(e,t->right);//去右子树删
	//这个节点就是要删的
	else if(t->left && t->right)//有两个子节点的节点
	{
		//找出右子树里最小的
		p = FindMin(t->right);
		t->data = p->data;
		t->right = DeleteTreeNode(t->data,t->right);
	}else//要删除的节点有一个子节点或就是叶子节点
	{
		p = t;
		if(t->left == NULL)//右数有
			t = t->right;
		else if(t->right == NULL)
			t = t->left;
		free(p);
		return t;
	}
	return t;

}

void DeleteTree(TREE **t)
{
	if(*t == NULL)
		return;
	DeleteTree(&((*t)->left));
	DeleteTree(&((*t)->right));
	free(*t);
	*t = NULL;
}

重点解释一下删除一个节点的算法:

包括两种情况,首先这种是要删除单子树节点的情况:

else//要删除的节点有一个子节点或就是叶子节点
{
	p = t;
	if(t->left == NULL)//右数有
		t = t->right;
	else if(t->right == NULL)
		t = t->left;
	free(p);
	return t;
}

image

这里是只有左子树,那么只要把他的左节点挂到根上面去。程序实现就是直接返回这个左节点。

image

image

如果要删除的是叶子节点,比如删除上图的3,那么执行第一条语句时:

if(t->left == NULL) t = t->right;

就已经把t赋值为右数,第二条赋值左树,都是NULL所以最终t就是NULL,返回的也就是NULL。

释放p,就是原来的t,就成功删除了叶子节点3.

image

image

第二种情况就是要删除的是有双子树的一个节点:

image

else if(t->left && t->right)//有两个子节点的节点
{
	//找出右子树里最小的
	p = FindMin(t->right);
	t->data = p->data;
	t->right = DeleteTreeNode(t->data,t->right);
}

我们可以找出右子树的最小的节点,当然也可以是左子树最大的节点,先把它的数据提上来,将它递归删除掉。

image

image

testBSTree.c

#include<stdio.h>
#include"tree.h"

void main()
{
	int n;
	TREE *tree = MakeEmptyTree(),*p;
	while(1)
	{
		printf("Please enter a num:");
		fflush(stdin);
		if(scanf("%d",&n) != 1)
			break;
		if(n == 0)
			break;
		tree = InsertTreeNode(n,tree);
	}
	printf("Max of tree is %d,min of tree is %d\n",
		FindMax(tree)->data,FindMin(tree)->data);


	fflush(stdin);
	printf("Please enter search num:");
	scanf("%d",&n);
	if(FindTreeNode(n,tree))
		printf("find %d\n",n);
	else
		printf("not find\n");

	p = DeleteTreeNode(n,tree);
	if(p)
		printf("delete %d success\n",n);
	else
		printf("delete fail\n");

	DeleteTree(&tree);
	if(tree == NULL)
		printf("delete success\n");
	else
		printf("fail\n");
}

运行时:

image

可以看到最大值输出76,最小值4,找到7,删除了7这个节点,进而删除了整棵树。

原文地址:https://www.cnblogs.com/shenerguang/p/2336968.html