binary search tree

转载 2016年06月01日 10:14:04

数据结构学习笔记二:二叉查找树

二叉查找树的特点:

(1)左边的所有节点都要小于根节点的值

(2)右边的所有节点都要不小于根节点的值

(3)原树的子树都符合(1)(2)条件。

二叉查找树又名二叉排序树,因为只需中序遍历它就可以得到排序的树了,对于二叉排序树的操作主要有:

(1)插入:通过插入来初始化树。本文是用链式,而不是存储在数组中。

(2)遍历:有三种方法分别为:先序,中序,后序。

(3)查找:有三种查找分别为:查找最大值,最小值,与某种特定的值的节点。

(4)删除:删除一个节点类型有三种分别为:无左右孩子的节点,有一个孩子的节点,有两个孩子的节点。

树是由节点和节点之间的边组成的,所以首先要声明一个节点类Node,一个节点有两个孩子和节点的值。

public class Node
{
    public  int value;
    public   Node leftChild;
    public  Node rightChild;
    public Node(int value)
    {
        leftChild = null;
        rightChild = null;
        this.value = value;
    }
}

节点类声明完成后,还需要一个树类,里面包含树的初始化以及一些对树的操作,一个默认构造函数来初始化一个空树和一个输出接点的值的函数。

class BinarySearchTree
{
    public  Node root;

    public BinarySearchTree()
    {
        root = null;
    }

    public void Dispaly(Node node)
    {
        Console.Write(node.value + " ");
    }
}

要构成一棵树,就得插入数值了,根据二叉排序树的性质,左边孩子的值全部小于根节点的值,所以在插入一个数值的时候

(1)首先判断是否为空树,也就是根节点是否为空,如果为空,就将插入的值放入根节点中。

(2)判断值与根节点(本树的根,或者其子数)值的大小,来判断放在左孩子还是右孩子。

public void Insert(int v)
{
    Node newNode = new Node(v);
    Node parent;
    Node current;
    if (root == null)
        root = newNode;
    else
    {
        current=root;
        while (true)
        { 
            parent=current;
            if (v < current.value)
            {
                current = current.leftChild;
                if (current == null)
                {
                    parent.leftChild = newNode;
                    break;
                }
            }
            else
            {
                current = current.rightChild;
                if (current == null)
                {
                    parent.rightChild = newNode;
                    break;
                }
            }
        }
    }
}

插入完成之后,一棵树就形成了,现在来遍历一下,三种遍历用递归实现,使逻辑更清晰

public void InOrder(Node root)
{
    Node node = root;
    if (node != null)
    {
        InOrder(node.leftChild);
        this.Dispaly(node);
        InOrder(node.rightChild);
    }
}
public void PreOrder(Node root)
{
    Node node = root;
    if (node != null)
    {
        this.Dispaly(node);
        PreOrder(node.leftChild);
        PreOrder(node.rightChild);
    }
}
public void PostOrder(Node root)
{
    Node node = root;
    if (node != null)
    {
        PostOrder(node.leftChild);
        PostOrder(node.rightChild);
        this.Dispaly(node);
    }
}
三种遍历是根节点的位序不同。接着就是查找树中的最大值,最小值,以及特定的值。
(1)最大值:在树的最右边的孩子
(2)最小值:在树的最左边的孩子
(3)特定值:用循环,判断与根值的大小。
public Node FindMax()
{ 
    Node current=root;
    while (current.rightChild != null)
        current = current.rightChild;
    return current;
}
public Node FindMin()
{
    Node current = root;
    while (current.leftChild != null)
        current = current.leftChild;
    return current;
}
public Node Find(int v)
{
    Node current = root;
    while (true)
    {
        if (v < current.value)
            current = current.leftChild;
        else if (v > current.value)
            current = current.rightChild;
        else
            return current;
        if (current == null)
            return null;
    }
}

最后就是删除了,由于使用链式构成的数,所以在树中删除一个节点的方法和在链表中删除一个节点的方法类似,只不过改动的“指针”更多一点,因为树的节点是一对多的。用if-else语句分别区分删除的三种类型的节点。

public bool Delete(int v)
{ 
    Node current=root;
    Node parent = current;
    //找到要删除的节点
    while (current.value != v)
    {
        parent = current;
        if (v < current.value)
        {
            current = current.leftChild;
        }
        else
        {
            current = current.rightChild;
        }
        if (current == null)
            return false;
    }
    //如果是没有孩子的节点
    if (current.leftChild == null && current.rightChild == null)
    {
        if (current == root)
            root = null;
         if (current ==parent.leftChild)
            parent.leftChild = null;
         if (current ==parent.rightChild)
            parent.rightChild = null;
    }
     //如果是有右孩子的节点
    else if (current.rightChild != null)
    {
        if (current == root)
            root = current.leftChild;
        if (current == parent.leftChild)
            parent.leftChild = current.rightChild;
        if (current == parent.rightChild)
            parent.rightChild = current.rightChild;
    }
    //如果是有左孩子的节点
    else if(current.leftChild!=null)
    {
        if(current==root)
            root=current.rightChild;
        if(current==parent.leftChild)
            parent.leftChild=current.leftChild;
        if(current==parent.rightChild)
            parent.rightChild=current.leftChild;
    }
    //有两个孩子的节点
    else
    {
        Node newNode=GetSuccessor(current);
        newNode.rightChild=current.rightChild;
        newNode.leftChild=current.leftChild;
        if(current==parent.leftChild)
            parent.leftChild=newNode;
        if(current==parent.rightChild)
            parent.rightChild=newNode;
    }
    return true;
}

其中查找successor节点的方法如下

/// <summary>
/// 删除一个有两个孩子的节点时,应该以中序遍历时将删节点delNode
/// 右邻节点successor(以删除的节点为子树的根节点,最左边的
/// 节点来替代被删的节点)来代替,因为successor的值是大于delNode 值中
/// 最小的
/// </summary>
/// <param name="delNode"></param>
/// <returns></returns>
private Node GetSuccessor(Node delNode)
{
    Node current = delNode;
    while (current.leftChild != null)
        current = current.leftChild;
    return current;
}

测试如下:

static void Main(string[] args)
{
    BinarySearchTree bs = new BinarySearchTree();
    bs.Insert(2);
    bs.Insert(5);
    bs.Insert(6);
    bs.Insert(10);
    bs.Insert(12);
    bs.Insert(15);
    bs.Insert(18);
    bs.InOrder(bs.root);
    Console.WriteLine("最大的数:{0}", bs.FindMax().value);
    Console.WriteLine("最小的数:{0}", bs.FindMin().value);
    Console.WriteLine("找到节点的值:{0}",bs.Find(6).value);
    bs.Delete(5);
    bs.InOrder(bs.root);
    Console.ReadKey();
}

输出:

image

总结:

(1)了解二叉排序树的基本原理,就要将其应用。

(2)应该还有顺序存储方式,本文是用链式。

(3)大道至简,从简至繁。

(4)如有错误或者建议请在回复中说明或者发送zabery@126.com

二叉搜索树(Binary Search Tree )的定义及分析

定义:     二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树: 每个结点都有一个作为搜索依据的关键码(key),所有结点的关键码互不相同。 左子树(如果非空)上所...
  • jsh13417
  • jsh13417
  • 2013年01月22日 21:59
  • 3417

数据结构-BST(Binary Search Tree)

/****************************************** 数据结构: BST(Binary Search Tree),二叉查找树; 性质: 若结点的左子树不空,则左子树...
  • Jarily
  • Jarily
  • 2013年03月15日 19:00
  • 7118

二叉搜索树(Binary Search Tree)的插入与删除

二叉搜索树的插入关键是要找到元素应该插入的位置,可以采用与Find类似的方法。 二叉搜索树的删除则要考虑三种情况:   1.要删除的是叶节点:直接删除,并再修改其父节点指针置为NULL ...
  • song_hui_xiang
  • song_hui_xiang
  • 2015年08月16日 13:10
  • 1011

Validate Binary Search Tree -- LeetCode

原题链接: http://oj.leetcode.com/problems/validate-binary-search-tree/  这道题是检查一颗二分查找树是否合法,二分查找树是非常常见的一种...
  • linhuanmars
  • linhuanmars
  • 2014年04月16日 04:34
  • 11685

二叉搜索树的查询、插入与删除操作(Binary Search Tree, Search, Insert, Delete)(C++)

一、概念     设 x 是二叉搜索树中的一个结点。如果 y 是 x 左子树中的一个结点,那么 y.key ≦ x.key。如果 y 是 x 右子树中的一个结点,那么 y.key ≧ x.key。 ...
  • zhangpiu
  • zhangpiu
  • 2015年11月19日 16:09
  • 1119

Recover Binary Search Tree -- LeetCode

原题链接: http://oj.leetcode.com/problems/recover-binary-search-tree/  这道题是要求恢复一颗有两个元素调换错了的二叉查找树。一开始拿到可...
  • linhuanmars
  • linhuanmars
  • 2014年04月27日 03:09
  • 15258

Leetcode 98. Validate Binary Search Tree C++及javascript解答,不同语言不同玩法

题意:给定一棵二叉树,写程序判断这颗二叉树是否为合法的二分查找树(对于节点root,其所有左子树中节点都满足 node.val root.val) 转载请注明出处:http://blog.csdn...
  • sunny606
  • sunny606
  • 2017年03月15日 22:03
  • 209

怎样判断一个二叉树是binary search tree

怎样判断一个二叉树是binary search tree 怎么实现 boolean isBST(Node *root)? 看看这个,简单明了 http://www.ardendertat....
  • kalium
  • kalium
  • 2012年05月17日 23:57
  • 1213

【LeetCode】Validate Binary Search Tree 解题报告

今天CSDN博客发生异常,折腾了大半天终于发出了这篇博文。 【题目】 Given a binary tree, determine if it is a valid binary sear...
  • ljiabin
  • ljiabin
  • 2014年12月03日 16:58
  • 9369

一个很全面的Binary Search Tree java实现

  • xx_snoopy
  • xx_snoopy
  • 2009年12月02日 23:14
  • 7238
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:binary search tree
举报原因:
原因补充:

(最多只允许输入30个字)