数据结构——二叉搜索树

1. 简介
   二叉搜索树中的关键字总是以满足二叉搜索树性质的方式来存储:
   设x是二叉搜索树中的一个结点。如果y是x的左子树的一个结点,那么y.key <= x.key 。如果y是x右子树中的一个结点,那么y.key >= x.key
  在下图中,,树根的关键字为6,在其左树中有关键字2、5和5,它们均不大于6;而在其右子树有关键字7和8,它们均不小于6。并且这个性质对于图中的每个结点都成立。


2. 遍历二叉树

  所谓遍历是指沿着某条搜索路径,依次对数中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题。遍历时二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。关于二叉树的遍历这边主要提及 前序遍历中序遍历后序遍历三种。
2.1 前序遍历
  前序遍历(先序遍历)中输出的根的关键字在其左右子树的关键字之前。因此前序遍历的递归算法依次执行如下操作:1. 访问根结点;2. 遍历左子树;3. 遍历右子树。
  因此对于上图的例子而言,前序遍历输出的关键字次序为:6,5,2,5,7,8.
2.2 中序遍历
  中序遍历输出的子树根的关键字位于其左子树的关键字和右子树的关键字之间。因此中序遍历的递归算法依次执行如下操作:1.遍历左子树;2. 访问根结点;3. 遍历右子树。
  因此对于上图的例子而言,中序遍历输出的关键字次序为:2,5,5,6,7,8.
2.3 后序遍历
  后序遍历输出的根的关键字在其左右子树的关键字之后。因此后序遍历的递归算法依次执行如下操作:1. 遍历左子树;2. 遍历右子树;3. 访问根结点。
  因此对于上图的例子而言,后序遍历输出的关键字次序为:2,5,5,7,8,6.
3. 二叉搜索树的实现
对于二叉树的存储结构有顺序存储结构和链式存储结构。这里我们以链式的存储结构为例。
/*********************************************************************************
*Copyright(C),Your Company
*FileName:  main.cpp
*Author:  Huangjh
*Version:
*Date:  2018-02-05
*Description:  二叉搜索树(C语言)实现
*Others:
**********************************************************************************/
#ifndef _TREE_H
#define _TREE_H

typedef int ElementType;

typedef void(*RETRIEVE)(ElementType);

struct _tree_node_t;
typedef struct _tree_node_t TreeNode;

struct _tree_node_t
{
	ElementType Element;
	struct _tree_node_t *pLeft;		//左孩子
	struct _tree_node_t *pRight;	//右孩子
};

TreeNode *newTreeNode(ElementType element);

void deleteTreeNode(TreeNode *pTreeNode);

TreeNode *makeEmpty(TreeNode *pTreeNode);

TreeNode *Find(TreeNode *pTreeNode, ElementType element);

TreeNode *FindMin(TreeNode *pTreeNode);

TreeNode *FindMax(TreeNode *pTreeNode);

TreeNode *Insert(TreeNode *pTreeNode, ElementType element);

TreeNode *Delete(TreeNode *pTreeNode, ElementType element);

void Retrieve(TreeNode *pTreeNode, RETRIEVE function);

void Retrieve2(TreeNode *pTreeNode, RETRIEVE function);

void Retrieve3(TreeNode *pTreeNode, RETRIEVE function);


#endif	//#ifndef _TREE_H
/*********************************************************************************
*Copyright(C),Your Company
*FileName:  main.cpp
*Author:  Huangjh
*Version:
*Date:  2018-02-05
*Description:  二叉搜索树(C语言)实现
*Others:
**********************************************************************************/
#include <stdlib.h>
#include "tree.h"

TreeNode *newTreeNode(ElementType element)
{
	TreeNode *pTreeNode = (TreeNode *)malloc(sizeof(TreeNode));
	if (pTreeNode != NULL)
	{
		pTreeNode->Element = element;
		pTreeNode->pLeft = NULL;
		pTreeNode->pRight = NULL;
		return pTreeNode;
	}
	return NULL;
}

void deleteTreeNode(TreeNode *pTreeNode)
{
	if (pTreeNode != NULL)
		free(pTreeNode);
}

TreeNode *makeEmpty(TreeNode *pTreeNode)
{	if (pTreeNode != NULL)
	{
		makeEmpty(pTreeNode->pLeft);
		makeEmpty(pTreeNode->pRight);
		deleteTreeNode(pTreeNode);
	}
	return NULL;
}

TreeNode *Find(TreeNode *pTreeNode, ElementType element)
{
	if (pTreeNode == NULL)
		return NULL;

	if (pTreeNode->Element > element)
		return Find(pTreeNode->pLeft, element);
	else if (pTreeNode->Element < element)
		return Find(pTreeNode->pRight, element);
	else
		return pTreeNode;
}

#if 1
TreeNode *FindMin(TreeNode *pTreeNode)
{
	if (pTreeNode != NULL)
		return NULL;

	if (pTreeNode->pLeft != NULL)
		return FindMin(pTreeNode->pLeft);
	else
		return pTreeNode;
}

TreeNode *FindMax(TreeNode *pTreeNode)
{
	if (pTreeNode != NULL)
		return NULL;

	if (pTreeNode->pRight != NULL)
		return FindMax(pTreeNode->pRight);
	else
		return pTreeNode;
}
#else
TreeNode *FindMin(TreeNode *pTreeNode)
{
	if (pTreeNode == NULL)
		return NULL;

	TreeNode *pMinNode = pTreeNode->pLeft;
	while (pMinNode != NULL)
		pMinNode = pMinNode->pLeft;

	return pMinNode;
}

TreeNode *FindMax(TreeNode *pTreeNode)
{
	if (pTreeNode == NULL)
		return NULL;

	TreeNode *pMaxNode = pTreeNode->pRight;
	while (pMaxNode != NULL)
		pMaxNode = pMaxNode->pRight;

	return pMaxNode;
}
#endif

TreeNode *Insert(TreeNode *pTreeNode, ElementType element)
{
	if (pTreeNode == NULL)
	{
		pTreeNode = newTreeNode(element);
		if (pTreeNode == NULL)
		{
			abort();
		}
	}
	else
	{
		if (element < pTreeNode->Element)
			pTreeNode->pLeft = Insert(pTreeNode->pLeft, element);
		else
			pTreeNode->pRight = Insert(pTreeNode->pRight, element);
	}

	return pTreeNode;
}

TreeNode *Delete(TreeNode *pTreeNode, ElementType element)
{
	TreeNode *pTempNode;

	if (pTreeNode == NULL)
	{ 
		return NULL;
	}
	else
	{
		if (element < pTreeNode->Element)
		{
			pTreeNode->pLeft = Delete(pTreeNode->pLeft, element);
		}
		else if (element > pTreeNode->Element)
		{
			pTreeNode->pRight = Delete(pTreeNode->pRight, element);
		}
		else
		{
			//左右子树均存在
			if (pTreeNode->pLeft && pTreeNode->pRight)
			{
				pTempNode = FindMin(pTreeNode->pRight);
				pTreeNode->Element = pTempNode->Element;
				pTreeNode->pRight = Delete(pTreeNode->pRight, pTreeNode->Element);
			}
			else
			{
				//只存在左/右或不存在子树
				pTempNode = pTreeNode;
				if (pTreeNode->pLeft == NULL)
					pTreeNode = pTreeNode->pRight;
				else if (pTreeNode->pRight == NULL)
					pTreeNode = pTreeNode->pLeft;
				
				free(pTempNode);
			}
		}
	}

	return pTreeNode;
}
//中序遍历
void Retrieve(TreeNode *pTreeNode, RETRIEVE function)
{
	if (pTreeNode == NULL)
	{
		return;
	}
	else
	{
		if (pTreeNode->pLeft != NULL)
			Retrieve(pTreeNode->pLeft, function);
		
		function(pTreeNode->Element);

		if (pTreeNode->pRight != NULL)
			Retrieve(pTreeNode->pRight, function);
	}
	return;
}

//前序遍历
void Retrieve2(TreeNode *pTreeNode, RETRIEVE function)
{
	if (pTreeNode == NULL)
	{
		return;
	}
	else
	{
		function(pTreeNode->Element);

		if (pTreeNode->pLeft != NULL)
			Retrieve(pTreeNode->pLeft, function);

		if (pTreeNode->pRight != NULL)
			Retrieve(pTreeNode->pRight, function);
	}
	return;
}

//后序遍历
void Retrieve3(TreeNode *pTreeNode, RETRIEVE function)
{
	if (pTreeNode == NULL)
	{
		return;
	}
	else
	{
		if (pTreeNode->pLeft != NULL)
			Retrieve(pTreeNode->pLeft, function);

		if (pTreeNode->pRight != NULL)
			Retrieve(pTreeNode->pRight, function);

		function(pTreeNode->Element);
	}
	return;
}
/*********************************************************************************
*Copyright(C),Your Company
*FileName:  main.cpp
*Author:  Huangjh
*Version:
*Date:  2018-02-06
*Description:  二叉搜索树(C语言)测试用例
*Others:
**********************************************************************************/
#include <stdio.h>
#include "tree.h"

void Display(ElementType elem)
{
	printf("%d\r\n", elem);
}

int main(void)
{
	TreeNode *pRoot = newTreeNode(6);
	if (pRoot == NULL)
		return -1;
	

	Insert(pRoot, 5);
	Insert(pRoot, 7);
	Insert(pRoot, 2);
	Insert(pRoot, 5);
	Insert(pRoot, 8);

	printf("中序遍历:\r\n");
	Retrieve(pRoot, Display);
	printf("前序遍历:\r\n");
	Retrieve2(pRoot, Display);
	printf("后序遍历:\r\n");
	Retrieve3(pRoot, Display);
	
	pRoot = makeEmpty(pRoot);

	return 0;
}
  运行结果如下所示:
中序遍历:
2
5
5
6
7
8
前序遍历:
6
2
5
5
7
8
后序遍历:
2
5
5
7
8
6


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值