/*
二叉搜索树(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二叉搜索树的实现的更多相关文章

  1. 二叉搜索树详解(Java实现)

    1.二叉搜索树定义 二叉搜索树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根 ...

  2. BinarySearchTree(二叉搜索树)原理及C++代码实现

    BST是一类用途极广的数据结构.它有如下性质:设x是二叉搜索树内的一个结点.如果y是x左子树中的一个结点,那么y.key<=x.key.如果y是x右子树中的一个结点,那么y.key>=x. ...

  3. javascript数据结构——写一个二叉搜索树

    二叉搜索树就是左侧子节点值比根节点值小,右侧子节点值比根节点值大的二叉树. 照着书敲了一遍. function BinarySearchTree(){ var Node = function(key) ...

  4. Java二叉搜索树实现

    树集合了数组(查找速度快)和链表(插入.删除速度快)的优点 二叉树是一种特殊的树,即:树中的每个节点最多只能有两个子节点 二叉搜索树是一种特殊的二叉树,即:节点的左子节点的值都小于这个节点的值,节点的 ...

  5. 数据结构-二叉树(应用篇)-之二叉搜索树 C和C++的实现

    一.概念 二叉搜索树(Binary Sort Tree/Binary Search Tree...),是二叉树的一种特殊扩展.也是一种动态查找表. 在二叉搜索树中,左子树上所有节点的均小于根节点,右子 ...

  6. Java与算法之(13) - 二叉搜索树

    查找是指在一批记录中找出满足指定条件的某一记录的过程,例如在数组{ 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }中查找数字15,实现代码很简单 ...

  7. 二叉搜索树(Java实现)

    二叉搜索树基本操作 求树中的结点个数 判断节点是否为空 向树中插入新结点key-value 树中是否存在key 返回树中key对应的value值 先序遍历 中序遍历 后续遍历 层序遍历 求树中key最 ...

  8. [数据结构]P2.1 二叉搜索树

    二叉树就是每个节点最多有两个分叉的树.这里我们写一写一个典型的例子二叉搜索树,它存在的实际意义是什么呢? 在P1.1链表中,我们清楚了链表的优势是善于删除添加节点,但是其取值很慢:数组的优势是善于取值 ...

  9. 【IT笔试面试题整理】二叉搜索树转换为双向链表

    [试题描述] 将二叉搜索树转换为双向链表 对于二叉搜索树,可以将其转换为双向链表,其中,节点的左子树指针在链表中指向前一个节点,右子树指针在链表中指向后一个节点. 思路一: 采用递归思想,对于二叉搜索 ...

随机推荐

  1. 在 Windows 8 中启用可匿名访问的共享

    就是不用输入用户名和密码,直接通过网上邻居可以访问的共享. 1.打开本地组策略编辑器(快捷键Win+R,打开运行,输入gpedit.msc,确定): 2.打开:"本地计算机策略->计算 ...

  2. 修改ultisnips的默认键

    把ultisnips修改和textmate一致. <tab>展开代码,再按<tab>跳转到下一个占位符,<shift+tab>跳转上一个占位符. 在vim配置文件中 ...

  3. JS教程:window.location使用方法的区别

    介绍了window.location使用方法的区别. window.location.href=&http://www.jbxue.com/javascript/ldquo;url”:改变ur ...

  4. js实现拉伸拖动iframe的具体代码

    这篇文章介绍了js实现拉伸拖动iframe的具体代码,有需要的朋友可以参考一下左边iframe放树目录,右边的iframe放index页.拖鼠标同时控制2个iframe的宽高.期待有人能改进.操作方法 ...

  5. 在FPGA中使用for循环一定浪费资源吗?

    渐渐地,发现自己已经习惯于发现细节,喜欢打破常规,真的非常喜欢这种feel. 相信很多人在书上或者博文上都有提出“在FPGA中使用for语句是很占用资源的”的观点,特权同学也不例外.那么,这种观点正确 ...

  6. ORACLE 11G在存储过程里面遍历游标, 调用job任务定时运行

    ORACLE存储过程里游标遍历.调用job定时运行 1,第一种使用For 循环 for循环是比較简单有用的方法. 首先.它会自己主动open和close游标.攻克了你忘记打开或关闭游标的烦恼. 其次, ...

  7. mac下framework联编需要设置的

    点击target,然后,在Build Phases里的空白处用鼠标点一下(艹 变态) 这时,点最上面菜单:Editor/Add Build Phases/Add Copy Files Build Ph ...

  8. hadoop集群搭建namenode无法启动问题

    一定要确保机器名没有下划线和.等特殊字符 搞了好久,终于找到了是上面这个原因. 搭建好了,下一步就是调优喽!

  9. ios开发中,xib加载view,loadNibNamed方法奔溃原因之一

    xib中某一属性在代码中已删除,但在xib中没有解除关联

  10. 一款基于jquery滑动后固定于顶部的导航

    之前已为大家介绍了好多css3实现的导航菜单.今天分享一款基于jquery滑动后固定于顶部的导航.这款导航的特点是初始位于顶部下面一百个像素,当鼠标滚动时到下方,导航一直处于顶部.效果图如下: 在线预 ...