BinarySearchTree二叉搜索树的实现
/*
二叉搜索树(Binary Search Tree),(又:二叉查找树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
*/
// BinarySearchTree.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <iostream> using std::cin;
using std::cout;
using std::endl; struct BinarySearchTreeNode{
int key;
BinarySearchTreeNode *parent;
BinarySearchTreeNode *left;
BinarySearchTreeNode *right;
}; struct BinarySearchTree{
BinarySearchTreeNode *root;
int nodes;
}; void initeTree(BinarySearchTree &T)
{
T.root = nullptr;
T.nodes = ;
} void allocateNodeSpace(BinarySearchTreeNode **node)
{
*node = (BinarySearchTreeNode *)malloc(sizeof(BinarySearchTreeNode));
if (*node == NULL)
cout << "allocte space error!"<<endl;
else
{
(*node)->left = nullptr;
(*node)->right = nullptr;
(*node)->parent = nullptr;
(*node)->key = ;
}
}
void inorderVisit(BinarySearchTreeNode *node)
{
if (node != nullptr)
{
inorderVisit(node->left);
cout << node->key << ' ';
inorderVisit(node->right);
}
} //递归实现
BinarySearchTreeNode &searchOneNode(BinarySearchTreeNode* node,int key)
{
if (node == nullptr || node->key == key)
return *node;
if (node->key < key)
return searchOneNode(node->right, key);
else
return searchOneNode(node->left,key); } //迭代实现
BinarySearchTreeNode &searchOneNode1(BinarySearchTreeNode* node, int key)
{
while (node != nullptr && key != node->key)
{
if (node->key < key)
node = node->right;
else
node = node->left;
}
return *node;
} //查找某个结点子树中的最小元素
BinarySearchTreeNode &findMinmum(BinarySearchTreeNode *node)
{
while (node->left != nullptr)
{
node = node->left;
}
return *node;
} //查找某个结点子树中的最大元素
BinarySearchTreeNode &findMaxmum(BinarySearchTreeNode *node)
{
while (node->right != nullptr)
{
node = node->right;
}
return *node;
} //获取一个结点的后继
//两种情况:
//1 结点x的右子树非空,那么x的后继结点恰是x的右子树中的最左结点。
//2 结点x的右子树为空,如果x有一个后继结点y,那么y就是x的有左孩子的最底层祖先,并且它也是x的一个祖先。
BinarySearchTreeNode &getNodeSuccessor(BinarySearchTreeNode *node)
{
BinarySearchTreeNode *ptr = nullptr;
ptr = node->right;
while (ptr != nullptr && ptr->left != nullptr)
{
ptr = ptr->left;
}
if (ptr == nullptr)
ptr = node->parent;
return *ptr;
} //建立一棵二叉搜索树,即向二叉搜索树中增加结点
void inserTreeNode(BinarySearchTree &T,BinarySearchTreeNode *node)
{
BinarySearchTreeNode *parentPtr = nullptr;
BinarySearchTreeNode *temPtr = T.root;
while (temPtr != nullptr)
{
parentPtr = temPtr;
if (node->key < temPtr->key)
temPtr = temPtr->left;
else
temPtr = temPtr->right;
}
node->parent = parentPtr;
if (parentPtr == nullptr)
T.root = node;
else if (node->key < parentPtr->key)
parentPtr->left = node;
else
parentPtr->right = node;
} //建立一棵二叉搜索树,即
void createTree(BinarySearchTree &T)
{
int key = -;
BinarySearchTreeNode *temNode = nullptr;
while (cin>>key,key!=-)
{ allocateNodeSpace(&temNode);
temNode->key = key;
inserTreeNode(T,temNode);
}
} //用一棵子树v替换另一棵子树u并成为其(u)双亲的孩子结点。
void transplantUV(BinarySearchTree &T,BinarySearchTreeNode *u, BinarySearchTreeNode *v)
{
if (u->parent == nullptr)
T.root = v;
else if (u == u->parent->left)
u->parent->left = v;
else
u->parent->right = v;
if (v != nullptr)
v->parent = u->parent;
}
//从二叉搜索树中删除一个结点
/*
从一棵二叉搜索树中删除一个结点node,可以分为三种情况:
1)如果node没有孩子结点,那么可以直接删除该结点;
2)如果node只有一个孩子结点,那么就让该孩子结点取代node的位置;
3)如果node有两个孩子结点,那么找到node的后继结点afterNode(一定在node的右子树中),并让afterNode取代node的位置。
并让node原来的右子树成为afterNode新的右子树,node的左子树成为afterNode的左子树。
对于情况3)又可以分为两种情况:
3.1)afterNode是node的右孩子,那么直接让afterNode取代node的位置,不做其它变换。
3.2)afterNode是node的右子树中的左子树的一个结点,但不是node的右孩子,那么先让afterNode的右孩子取代afterNode的位置,
然后让afterNode取代node的位置,并让node的右子树成为afterNode新的右子树。
*/
void deleteTreeNode(BinarySearchTree &T, int key)
{
BinarySearchTreeNode *node = &searchOneNode1(T.root,key);
if (node->left == nullptr)
transplantUV(T, node, node->right);
else if (node->right == nullptr)
transplantUV(T,node,node->left);
else
{
BinarySearchTreeNode *temPtr = &findMinmum(node->right);
if (temPtr->parent != node)
{
transplantUV(T,temPtr,temPtr->right);
temPtr->right = node->right;
temPtr->right->parent = temPtr;
}
transplantUV(T, node, temPtr);
temPtr->left = node->left;
node->left->parent = temPtr;
}
free(node);
} void main(void)
{
cout << "1.首先构建一棵二叉搜索树:" << endl;
BinarySearchTree T;
initeTree(T);
createTree(T);
cout << "2.中序遍历二叉搜索树:" << endl;
inorderVisit(T.root);
//cout << endl;
//cout << "3.输入出一个结点的后继结点:" << endl;
//cout << "请输入要查找的结点的关键字Key:" << endl;
//int keyValue;
//cin >> keyValue;
//BinarySearchTreeNode *temPtr = &searchOneNode1(T.root,keyValue);
//BinarySearchTreeNode *successorPtr = &getNodeSuccessor(temPtr);
//cout << successorPtr->key;
//cout << "请输入要删除的结点的关键字:" << endl;
//cin >> keyValue;
int keyValue;
cin >> keyValue;
deleteTreeNode(T, keyValue);
inorderVisit(T.root);
}
对于查找一个结点x的后继结点来说,其第二种情况即:如果结点x没有右子树,那么对于x的父结点来说又可以分为两种情况,1)x结点在其父结点的左子树上;2)x结点在其父结点的右子树上。当然我们不可能这样无休止的分析下去,因为相对于x结点的所有祖先来说,x结点所在的位置情况都有两种。若是x结点有n个祖先,那么就会出现2n中情况。所以可以另辟蹊径,那我们从遍历二叉搜索树着手。试想一下,我们可以通过中序遍历一棵二叉搜索树得到一串有序序列。那么对于中序遍历来说,其x结点的后继就是我们要找的点。如果结点x在中序遍历序列中不是最后一个结点的话,那么它必有一个后继结点(线性表的性质)。
好,假如对于一个结点x,其后继结点y存在,那么y->key一定大于x->key。我们可以这样考虑:
根据二叉搜索树的性质,我们知道x的左子树中的任一结点的key值都小于x,所以y必定不在其左子树中。那么结点y必定为x的最先结点或者其祖先结点的右子树。而且y的key值是其中大于x的key值且最小的一个,所以y结点不可能是其祖先的右子树上的 结点。接着我们就可以确定y必定是x的祖先结点,x结点必定在y的左子树中,也就是说y的左孩子也是x的祖先,那么对于所有满足条件的祖先结点有n个(pi-1<pi)其中i = 0,1,...,n-1.由此可以推知,x的后继结点必定为其中最小的一个即p0。得到一个结论:结点x的右子树为空,如果x有一个后继结点y,那么y就是x的有左孩子的最底层祖先,并且它也是x的一个祖先。
BinarySearchTree二叉搜索树的实现的更多相关文章
- 二叉搜索树详解(Java实现)
1.二叉搜索树定义 二叉搜索树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根 ...
- BinarySearchTree(二叉搜索树)原理及C++代码实现
BST是一类用途极广的数据结构.它有如下性质:设x是二叉搜索树内的一个结点.如果y是x左子树中的一个结点,那么y.key<=x.key.如果y是x右子树中的一个结点,那么y.key>=x. ...
- javascript数据结构——写一个二叉搜索树
二叉搜索树就是左侧子节点值比根节点值小,右侧子节点值比根节点值大的二叉树. 照着书敲了一遍. function BinarySearchTree(){ var Node = function(key) ...
- Java二叉搜索树实现
树集合了数组(查找速度快)和链表(插入.删除速度快)的优点 二叉树是一种特殊的树,即:树中的每个节点最多只能有两个子节点 二叉搜索树是一种特殊的二叉树,即:节点的左子节点的值都小于这个节点的值,节点的 ...
- 数据结构-二叉树(应用篇)-之二叉搜索树 C和C++的实现
一.概念 二叉搜索树(Binary Sort Tree/Binary Search Tree...),是二叉树的一种特殊扩展.也是一种动态查找表. 在二叉搜索树中,左子树上所有节点的均小于根节点,右子 ...
- Java与算法之(13) - 二叉搜索树
查找是指在一批记录中找出满足指定条件的某一记录的过程,例如在数组{ 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }中查找数字15,实现代码很简单 ...
- 二叉搜索树(Java实现)
二叉搜索树基本操作 求树中的结点个数 判断节点是否为空 向树中插入新结点key-value 树中是否存在key 返回树中key对应的value值 先序遍历 中序遍历 后续遍历 层序遍历 求树中key最 ...
- [数据结构]P2.1 二叉搜索树
二叉树就是每个节点最多有两个分叉的树.这里我们写一写一个典型的例子二叉搜索树,它存在的实际意义是什么呢? 在P1.1链表中,我们清楚了链表的优势是善于删除添加节点,但是其取值很慢:数组的优势是善于取值 ...
- 【IT笔试面试题整理】二叉搜索树转换为双向链表
[试题描述] 将二叉搜索树转换为双向链表 对于二叉搜索树,可以将其转换为双向链表,其中,节点的左子树指针在链表中指向前一个节点,右子树指针在链表中指向后一个节点. 思路一: 采用递归思想,对于二叉搜索 ...
随机推荐
- 生产环境JAVA进程高CPU占用故障排查
问题描述:生产环境下的某台tomcat7服务器,在刚发布时的时候一切都很正常,在运行一段时间后就出现CPU占用很高的问题,基本上是负载一天比一天高. 问题分析:1,程序属于CPU密集型,和开发沟通过, ...
- Java:集合,Map接口框架图
Java集合大致可分为Set.List和Map三种体系,其中Set代表无序.不可重复的集合:List代表有序.重复的集合:而Map则代表具有映射关系的集合.Java 5之后,增加了Queue体系集合, ...
- Oracle 12C 在 Oracle Linux 6.5 64Bit 安装手冊
Oracle 12C 在 Oracle Linux 6.5 64Bit 安装手冊.step by step 下载地址: http://download.csdn.net/detail/rlhua/7 ...
- hdoj1069 Monkey and Banana
Monkey and Banana Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others ...
- 【Maven】Maven的安装与入门使用
它也是实现项目各个环节的好帮手,如编译.单元测试.打包.发布,等等.按照它的流程走,可以让我们养成严谨的习惯. 同时,我们用得很多的是用它下载JAR,想想以前,以前框架的包都是自己一个一个爬官网下载的 ...
- Solr学习之四-Solr配置说明之二
上一篇的配置说明主要是说明solrconfig.xml配置中的查询部分配置,在solr的功能中另外一个重要的功能是建索引,这是提供快速查询的核心. 按照Solr学习之一所述关于搜索引擎的原理中说明了建 ...
- LeetCode: Trapping Rain Water 解题报告
https://oj.leetcode.com/problems/trapping-rain-water/ Trapping Rain WaterGiven n non-negative intege ...
- JavaScript高级 面向对象(4)--值类型和引用类型
说明(2017.3.30): 1. 变量只存数据本身就是值类型,如var a = 123, var a = "123"; 变量存的是一个引用,数据存在别的地方,就是引用类型,如数 ...
- 2013年五大主流浏览器 HTML5 和 CSS3 兼容性大比拼【转】
摘要: 这篇文章给大家带来<五大主流浏览器 HTML5 和 CSS3 兼容性大比拼>,让我们一起来看看2013年的浏览器现状.浏览器厂商之间的竞争促使各大浏览器对 HTML5 和 CSS3 ...
- Curator入门教程1
简介 Curator是Netflix开源的一套ZooKeeper客户端框架. Netflix在使用ZooKeeper的过程中发现ZooKeeper自带的客户端太底层, 应用方在使用的时候需要自己处理 ...