任何BST树中节点的正确结构是什么

时间:2015-06-23 17:49:05

标签: c++ algorithm binary-search-tree

基于理论为二叉树创建节点的正确方法是什么? 例如:

struct Node
{
    int data;
    Node *left;
    Node *right;
};

我目前面临的问题是,我有几个来源(书籍,网站,在线讲座等)的2个不同答案。

从“算法导论”,第3版,第286,287页:“除了密钥和卫星数据外,每个节点还包含左,右和p属性,指向对应于其左子节点的节点,右边的子节点和它的父母分别。“

这意味着:

struct Node
{
   int data;
   Node *parent;
   Node *left;
   Node *right;
};

另一方面,我发现了几个不遵循这种设计的链接,例如:

http://algs4.cs.princeton.edu/32bst/

http://math.hws.edu/eck/cs225/s03/binary_trees/

http://www.cprogramming.com/tutorial/lesson18.html

这些实现不会保留与父母的链接,而且从一些在线讲座中可以看出,树木不会向后移动(也就是说,看不到父母),这反映了书中的概念!

在RedBlack树中,您需要查看该节点的祖父母和叔叔以确定是否重新着色和/或旋转以重新平衡树。 在AVL树中,你没有,因为焦点在于子树的高度。 四叉树和八叉树与您不需要父树一样。

问题:

有人可以回答我这个并且有效的资料来解释哪个是为二元树或任何树(B树,等等)设计节点的正确方法?

还有向后穿越的规则是什么?我知道用于遍历的预订,有序,后序,广度优先,深度优先(预订)和其他AI启发式算法。

你是不是可以在树上向后移动,即从孩子到父母?如果是这样,那么为什么这本书会建议到父节点的链接?

6 个答案:

答案 0 :(得分:5)

基本的二元树(基础)需要子指针:

struct binary_tree_node
{
  binary_tree_node * left_child;
  binary_tree_node * right_child;
};

可以对基础进行许多修改,以帮助促进搜索或存储。

这些可包括(但不限于):

  • 父指针
  • 子指针数组
  • “颜色”指示器
  • 专门的叶节点 - 没有子链接

设施取决于数据结构的使用。例如,子节点数组可以帮助加速I / O访问,其中读取“页面”节点与读取单个节点一样有效(参见B-Tree)。 “颜色”指示器可以帮助做出平衡决定。专门的“叶子”节点减少了树占用的内存量。

对于遍历,可以在任何方法中遍历树。没有规则阻止从子项到父项的遍历。一些遍历可能包括兄弟姐妹的兄弟姐妹。

有些书籍或网站可能会选择传统或基本的“二叉树”数据结构。我发现限制会妨碍你。

答案 1 :(得分:1)

没有硬性规定在树数据结构中必须有一个返回父级的链接。返回父级的链接类似于双向链表。没有回到父级的链接只是一个链表。通过反向链接,显然您可以获得更大的灵活性,但代价是(相对)更复杂的实现。许多问题可以通过链表解决,而其他一些则需要双重链表。

答案 2 :(得分:1)

没有任何规范定义。

通常,命令式语言(例如,C ++)倾向于支持父母方法。它简化了有效重新平衡的实现,并且正如Thomas Matthews指出的那样,它促进了恒定空间迭代。

功能语言(例如Haskell)倾向于使用无父方法(参见Purely Functional Data Structures)。由于无法进行任何修改,因此无论如何都要通过沿搜索路径重新进行所有重新平衡来完成,因此不需要后向指针。面向强递归,恒定空间迭代器的设计也不是很重要。

答案 3 :(得分:1)

这取决于你的任务

确实说binary search tree是一个概念,设计数据结构没有严格或标准的规则。但要了解基本功能(例如插入,删除,查找等),人们使用非常基本的数据结构,如

struct Node
{
    int data;
    Node *left;
    Node *right;
};

但是你的任务可能是为了不同的目的而设计不同的。例如,如果您需要在单个操作中找到tree node,则在任务的某个时刻给定parent node,您可能会考虑将节点结构设计为,

struct Node
{
    int data;
    Node *parent;
    Node *left;
    Node *right;
};

其他一些复杂的实现也可能需要存储兄弟姐妹列表。这将是,

 struct Node
 {
     int data;
     Node *parent;
     Node *left;
     Node *right;
     list<Node> *siblings;
 };

因此,没有严格的标准

答案 4 :(得分:-1)

struct tree_node
{
  tree_node* left_child;
  tree_node* right_child;
  int data;  // here you can use whatever type or data you want. Even generic type
};

答案 5 :(得分:-1)

以下节点定义(在Java中)用于平衡二叉树而不是BST。

// Copyright (C) NNcNannara 2017

public class Node
{
    public Node Left;
    public Node Right;
    public Node Parent;
    public State Balance;

    public Node()
    {
        Left = this;
        Right = this;
        Parent = null;
        Balance = State.Header;
    }

    public Node(Node p)
    {
        Left = null;
        Right = null;
        Parent = p;
        Balance = State.Balanced;
    }

    public Boolean isHeader ()
    { return Balance == State.Header;  }
}

这是为平衡例程而优化的。集节点从Node派生的想法如下。

// Copyright (C) NNcNannara 2017

public class SetNode<T> extends Node
{
    public T Data;

    public SetNode(T dataType, Node Parent)
    {
        super(Parent);
        Data = dataType;
    }
}

字典节点如下。

// Copyright (C) NNcNannara 2017

public class DictionaryNode<K, T> extends Node
{
    public T Data;
    public K Key;

    public DictionaryNode(K keyType, T dataType, Node Parent)
    {
        super(Parent);
        Key = keyType;
        Data = dataType;
    }
}

平衡和迭代本质上是非泛型的,并且是为基类Node定义的。当然,二进制树也可能存在于磁盘上,其中节点类型如下。

package persistent;

public class Node
{
    public long Left;
    public long Right;
    public long Parent;
    public long Key;
    public calculus.State Balance;

    public Node()
    {
        Left = 0;
        Right = 0;
        Parent = 0;
        Balance = calculus.State.Header;
        Key = 0;
    }

    public Node(long p)
    {
        Left = 0;
        Right = 0;
        Parent = p;
        Balance = calculus.State.Balanced;
        Key = 0;
    }

    public Boolean IsHeader ()  { return Balance == calculus.State.Header; }
}

不存在引用,而是存在节点和数据文件中的长整数偏移。请注意,磁盘上的所有集合只有一种节点类型。