还在乱找资料吗?关于树和二叉树的基础知识,看这一篇就够了。

301 阅读31分钟

1、树的基本概念和三种排序

1.树的常用概念
根节点(Root)、叶子节点(Leaf)、父节点(Parent)、子节点(Child)、兄弟节点(Siblings),还有节点的高度、深度以及层数,树的高度。

Root: Top node in a tree
Child: Nodes that are next to each other and connected downwards
Parent: Converse notion of child
Siblings: Nodes with the same parent
Descendant: Node reachable by repeated proceeding from parent to child
Ancestor: Node reachable by repeated proceeding from child to parent.
Leaf: Node with no children
Internal node: Node with at least one child
External node: Node with no children

2.概念解释
节点:树中的每个元素称为节点
父子关系:相邻两节点的连线,称为父子关系
根节点:没有父节点的节点
叶子节点:没有子节点的节点
父节点:指向子节点的节点
子节点:被父节点指向的节点
兄弟节点:具有相同父节点的多个节点称为兄弟节点关系
节点的高度:节点到叶子节点的最长路径所包含的边数
节点的深度:根节点到节点的路径所包含的边数
节点的层数:节点的深度+1(根节点的层数是1)
树的高度:等于根节点的高度

二叉树

1.概念
①什么是二叉树?
每个节点最多只有2个子节点的树,这两个节点分别是左子节点和右子节点。

②什么是满二叉树?
有一种二叉树,除了叶子节点外,每个节点都有左右两个子节点,这种二叉树叫做满二叉树。如下图2
③什么是完全二叉树?
有一种二叉树,叶子节点都在最底下两层,最后一层叶子节都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大,这种二叉树叫做完全二叉树。如下图3

完全二叉树的存储
非完全二叉树的存储,浪费内存

什么是平衡二叉树?
树上任意节点的左子树和右子树的深度之差不超过1

2.完全二叉树的存储


①链式存储
每个节点由3个字段,其中一个存储数据,另外两个是指向左右子节点的指针。我们只要拎住根节点,就可以通过左右子节点的指针,把整棵树都串起来。这种存储方式比较常用,大部分二叉树代码都是通过这种方式实现的。

C语言实现二叉树的创建

/* Includes structure for a node and a newNode() function which
   can be used to create a new node in the tree. 
   It is assumed that the data in nodes will be an integer, though
   function can be modified according to the data type, easily.
 */

#include <stdio.h>
#include <stdlib.h>

struct node
{
    struct node *leftNode;
    int data;
    struct node *rightNode;
};

struct node *newNode(int data)
{
    struct node *node = (struct node *)malloc(sizeof(struct node));

    node->leftNode = NULL;
    node->data = data;
    node->rightNode = NULL;

    return node;
}

int main(void)
{
    /* new node can be created here as :-

       struct node *nameOfNode = newNode(data);

       and tree can be formed by creating further nodes at
       nameOfNode->leftNode and so on.
    */

    return 0;
}

②顺序存储
用数组来存储,对于完全二叉树,如果节点X存储在数组中的下标为i,那么它的左子节点的存储下标为2

i,右子节点的下标为2
i+1,反过来,下标i/2位置存储的就是该节点的父节点。注意,根节点存储在下标为1的位置。完全二叉树用数组来存储时最省内存的方式。


3.二叉树的遍历


①前序遍历:对于树中的任意节点来说,先打印这个节点,然后再打印它的左子树,最后打印它的右子树。
②中序遍历:对于树中的任意节点来说,先打印它的左子树,然后再打印它的本身,最后打印它的右子树。
③后序遍历:对于树中的任意节点来说,先打印它的左子树,然后再打印它的右子树,最后打印它本身。


前序遍历的递推公式:
preOrder(r) = print r->preOrder(r->left)->preOrder(r->right)
中序遍历的递推公式:
inOrder(r) = inOrder(r->left)->print r->inOrder(r->right)
后序遍历的递推公式:
postOrder(r) = postOrder(r->left)->postOrder(r->right)->print r
时间复杂度:3种遍历方式中,每个节点最多会被访问2次,所以时间复杂度是O(n)。

C语言二叉树三种遍历的实现

/* Includes the functions for Recursive Traversals
   of a Binary Tree. It is assumed that nodes and
   tree have been created as per create_node.c
 */

#include <stdio.h>

void inOrderTraversal(struct node *node)
{
    if(node == NULL) //if tree is empty
        return;

    inOrderTraversal(node->leftNode);
    printf("\t%d\t", node->data);
    inOrderTraversal(node->rightNode);
}

void preOrderTraversal(struct node *node)
{
    if(node == NULL) //if tree is empty
        return;

    printf("\t%d\t", node->data);
    preOrderTraversal(node->leftNode);
    preOrderTraversal(node->rightNode);
}

void postOrderTraversal(struct node *node)
{
    if(node == NULL) //if tree is empty
        return;

    postOrderTraversal(node->leftNode);
    postOrderTraversal(node->rightNode);
    printf("\t%d\t",node->data);
}

int main(void)
{
    /* traversals can be done by simply invoking the
       function with a pointer to the root node.
    */

    return 0;
}

三种遍历的示范:

值得注意的是,当你删除树中的节点时,删除过程将按照后序遍历的顺序进行。 也就是说,当你删除一个节点时,你将首先删除它的左节点和它的右边的节点,然后再删除节点本身。

另外,后序在数学表达中被广泛使用。 编写程序来解析后缀表示法更为容易。 这里是一个例子:

您可以使用中序遍历轻松找出原始表达式。 但是程序处理这个表达式时并不容易,因为你必须检查操作的优先级。

如果你想对这棵树进行后序遍历,使用栈来处理表达式会变得更加容易。 每遇到一个操作符,就可以从栈中弹出栈顶的两个元素,计算并将结果返回到栈中。

下面继续讲解,三种遍历的非递归实现:
来自:二叉树的非递归前序、中序、后序遍历算法详解及代码实现(C语言) 这篇文章

从当前节点开始遍历:(当入栈时访问节点内容,则为前序遍历;出栈时访问,则为中序遍历)

  1. 若当前节点存在,就存入栈中,并访问左子树;

  2. 直到当前节点不存在,就出栈,并通过栈顶节点访问右子树;

  3. 不断重复12,直到当前节点不存在且栈空。

typedef struct TreeNode{
    int data;
    struct TreeNode *lChild;
    struct TreeNode *rChild;
}TreeNode;


//先序遍历的非递归实现

void preOrder(TreeNode *T){
    TreeNode *stack[15];
    int top = -1;
    TreeNode *p = T;
    while(p!=NULL||top!=-1){
        if(p!=NULL){
            stack[++ top] = p;
            printf("%d\t",p->data); //入栈时,访问输出
            p = p->lChild;
        }else{
            p = stack[top --];
            p = p->rChild;
        }
    }
}

//中序遍历的非递归实现

void inOrder(TreeNode *T){
    TreeNode *stack[15];
    int top = -1;
    TreeNode *p = T;
    while(p!=NULL||top!=-1){
        if(p!=NULL){
            stack[++ top] = p;
            p = p->lChild;
        }else{
            p = stack[top --];
            printf("%d\t",p->data);  //出栈时,访问输出
            p = p->rChild;
        }
    }
}


后序遍历整体与前中序遍历过程相似。但要注意,这时对于父节点的访问输出,需要在其右子树遍历完成的前提下进行。所以不能像前中序遍历一样,在遍历完左子树后,就直接出栈。我们需要利用这个未出栈的栈顶元素去获取右子树,在遍历完右子树后,就可以出栈,并对此节点进行访问输出。

这里我们需要使用一个标记,以区分是从左子树取栈还是从右子树出栈:(如图所示)

从当前节点开始遍历:

  1. 若当前节点存在,就存入栈中,并且置节点flag为1(第一次访问),然后访问其左子树;

  2. 直到当前节点不存在,需要回退,这里有两种情况:

    1)当栈顶节点flag为1时,则表明是从左子树回退,这时需置栈顶节点flag为2(第二次访问),然后通过栈顶节点访问其右子树(取栈顶节点用,但不出栈)
    
    2)当栈顶节点flag为2时,则表明是从右子树回退,这时需出栈,并取出栈节点做访问输出。(需要注意的是,输出完毕需要置当前节点为空,以便继续回退。具体可参考代码中的p = NULL)
    
  3. 不断重复12,直到当前节点不存在且栈空。
    相关代码:

void postOrder(TreeNode *T){
    TreeNode *stack[15];
    int top = -1;
    int flagStack[15];   //记录每个节点访问次数栈
    TreeNode *p = T;
    while(p!=NULL||top!=-1){
        if(p!=NULL){     //第一次访问,flag置1,入栈
            stack[++ top] = p;
            flagStack[top] = 1;   
            p = p->lChild;
        }else{//(p == NULL)
            if(flagStack[top] == 1){  //第二次访问,flag置2,取栈顶元素但不出栈
                p = stack[top];
                flagStack[top] = 2;
                p = p->rChild;
            }else{         //第三次访问,出栈
                p = stack[top --];
                printf("%d\t",p->data);    //出栈时,访问输出
                p = NULL;      //p置空,以便继续退栈
            }
        }
    }
}

二叉树的层次遍历:
实现思路:
一个二叉树,层次遍历就是每一行每一行的取出数据。
这个图的结果就是 ABCDEFGH


就是先父节点进入队列,然后循环,出队时带入下一组子节点进队,没有就没有进入队列的,当队列为空时结束循环。


伪代码如下:


完整代码参考文章最后。

2、 二叉查找树(binary search tree) BST tree

1,二叉查找树最大的特点是:支持动态数据集合的快速插入,删除,查找操作
2,二叉查找树的要求:在树中的任意一个节点,其中左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。

3,二叉查找树的查找操作


先取根节点,如果他等于要查找的数据,就返回。如果要查找的数据比根节点的值小,那就在左子树中递归查找;如果要查找的数据比根节点的值大,那就在右子树中递归查找



Java语言实现,查找操作,这里我添加递归和非递归两种方式

public class BinarySearchTree {

/**
*二叉查找树-查找-非递归实现
*/
  public Node find(Node tree, int data) {
    while (tree != null) {
      if (data < tree.data) tree = tree.left;
      else if (data > p.data) tree = tree.right;
      else return tree;
    }
    return null;
  }


/**
*二叉查找树-查找-递归实现
*/
  public Node findInRecursion(Node tree, int data){
    if(tree ==null) return null;
    if(tree.data<data) 
      tree=findInRecursion(tree.right,data);
    if(tree.data>data)
      tree=findInRecursion(tree.left,data);
  }


  public static class Node {
    private int data;
    private Node left;
    private Node right;

    public Node(int data) {
      this.data = data;
    }
  }
}



4,二叉查找树的插入操作


二叉查找树的插入过程有些类似查找操作。新插入的数据一般都是在叶子节点上,所以只需要从根节点开始,依次比较要插入的数据和节点的大小关系。
如果要插入的数据比节点的数据大,并且节点的右子树为空,就将新数据直接插入右子节点的位置;如果不为空,就在递归遍历右子树,查找插入位置。


java语言实现二叉查找树的插入操作,,这里我添加递归和非递归两种方式

/**
*二叉查找树-插入-非递归实现
*/
public Node insert(Node tree, int data) {
  if (tree == null) {
    tree = new Node(data);
    return tree;
  }

  Node p = tree;
  while (p != null) {
    if (data > p.data) {
      if (p.right == null) {
        p.right = new Node(data);
        return p.right;
      }
      p = p.right;
    } else { // data < p.data
      if (p.left == null) {
        p.left = new Node(data);
        return p.left;
      }
      p = p.left;
    }
  }
}


/**
*二叉查找树-插入-递归实现
*/
public void insertInRecursion(Node tree, int data){
   if(tree ==null) return new Node(val);
    if(tree.data<data) 
      insertInRecursion(tree.right,data);
    if(tree.data>data)
      insertInRecursion(tree.left,data);
}


5,二叉查找树的删除操作
二叉查找树的删除要分三种情况:
①:如果要删除的节点没有子节点,只需要直接将父节点中指向要删除节点的指针置为为null。


②:如果要删除的节点只有一个子节点(只有左子节点或者右子节点),我们只需要更新父节点中,指向要删除节点的指针,让它指向要删除节点的子节点就可以了。


③:如果要删除的节点有两个子节点,我们需要找到这个节点的右子节点肯定没有左子节点(如果有左子结点,那就不是最小节点了),所以就可以应用上面两条规则来删除这个最小节点。

java语言实现,二叉树的删除操作

/**
*二叉查找树-删除-递归实现
*/
public void delete(Node tree, int data) {
  // Node p = tree; // p指向要删除的节点,初始化指向根节点
  Node pp = null; // pp记录的是p的父节点
  while (p != null && p.data != data) {
    pp = p;
    if (data > p.data) p = p.right;
    else p = p.left;
  }
  if (p == null) return; // 没有找到

  // 要删除的节点有两个子节点
  if (p.left != null && p.right != null) { // 查找右子树中最小节点
    Node minP = p.right;
    Node minPP = p; // minPP表示minP的父节点
    while (minP.left != null) {
      minPP = minP;
      minP = minP.left;
    }
    p.data = minP.data; // 将minP的数据替换到p中
    p = minP; // 下面就变成了删除minP了
    pp = minPP;
  }

  // 删除节点是叶子节点或者仅有一个子节点
  Node child; // p的子节点
  if (p.left != null) child = p.left;
  else if (p.right != null) child = p.right;
  else child = null;

  if (pp == null) tree = child; // 删除的是根节点
  else if (pp.left == p) pp.left = child;
  else pp.right = child;
}

/**
*二叉查找树-删除-递归实现
*/
public Node deleteInRecursion(Node node, int data){
   if(tree ==null) return null;
   if(tree.data == data){
    //处理删除根结点且根无左右子树,删除根结点且根无左子树,删除根结点且根无右子树三种情况
      if(root.left == null) return node.right;
      if(root.right == null) return node.left;
      //处理删除跟结点,且其有左右子树的情况,这里用右子树的最小结点取代当前根结点
      Node minNode= getMin(node.right);
      node.data= minNode.data;
      root.right=deleteInRecursion(root.right,minNode.data)
   }
    else if(tree.data<data) 
      insertInRecursion(tree.right,data);
    else if(tree.data>data)
      insertInRecursion(tree.left,data);
}

public Node getMin(Node node){
  //BST中最左边的就是最小的
  while(tree.left!=null) node =node.left;
  return node;

}

6,二叉查找树的其他操作


除了插入,删除,查找操作之外,二叉查找树中还可以可以支持快速地查找最大节点和最小节点,前驱节点和后继节点。
二叉查找树还有一个重要的特性:中序遍历二叉查找树,可以输出有序的数据序列,时间复杂度是O(n),非常高效。因此,二叉查找树也叫二叉排序树。

7,二叉查找树支持重复数据


在实际开发中,是在二叉查找树中存储的对象,我们利用对象的某个字段作为键值(key)来构建二叉查找树,并把对象中的其他字段叫作卫星数据。

针对:如果存储两个对象键值相同的处理方式:

第一种方式:二叉查找树中每个节点不仅会存储一个数据,因此可通过链表和支持动态扩容的数组等数据结构,把值相同的数据都存储在同一个节点上。


第二种方式:每个节点仍然只存储一个数据,在查找插入位置的过程中,如果碰到一个节点的值,与要插入数据的值相同,我们就将这个要插入的数据放到这个节点的右子树,即把这个新插入的数据当做大于这个节点的值来处理。

这样当要查找数据时,遇到值相同的节点,不通知查找操作,而是继续在右子树中查找,直到遇到叶子节点,才停止。
删除操作,也需要先查找到每个要删除的节点,然后在按前面讲的删除操作的方法,依次删除。

8,二叉查找树的时间复杂度分析


二叉查找树的形态多种多样,每种的查找,插入,删除操作的执行效率都不一样。
但,不管操作是插入,删除还是查找,时间复杂度其实都根树的高度正比,即O(height)。
树的高度等于最大层数减一,每层包含的节点个数是2(k-1)。但对于完全二叉树,最后一层节点个数不遵守这个规律。它包含的节点个数在1个到2(L-1)个之间(假设最大层数是L)。


如果将每一层的节点数加起来就是总的节点个数n。则n满足以下关系:
n>=1+2+4+8+……+2^(L-2)+1
n<=1+2+4+8+……+2(L-2)+2(L-1)
得到L的范围是[log2(n+1),log2n +1]。


完全二叉树的层数小于等于log2^n + 1,即完全二叉树的高度小于等于log2^n
所以,极度不平衡的二叉查找树,它的查找性能肯定不能满足我们的需求。我们需要构建一种不管怎么删除,插入数据,在任何时候,都能保持任意节点左右子树都比较平衡的二叉查找树—平衡二叉查找树。

散列表无法替代二分查找树的原因:


1,散列表中的数据是无序存储的,若要输出有序的数据,需要先进行排序。而对于二叉查找树来说,我们只需要中序遍历,就可以在O(n)的时间复杂度内,输出有序的数据序列。
2,散列表扩容耗时很多,而且当遇到散列冲突时,性能不稳定,在工程中常用的二叉查找树的性能非常稳定,时间复杂度稳定在O(logn。


3,笼统地讲,虽然散列表的查找操作的时间复杂度是常量级的,但因为哈希冲突的存在,这个个常量不一定比logn小,所以实际查找速度可能不一定比O(logn)快。加上哈希函数的耗时,也不一定比平衡二叉查找树的效率高。


4,散列表的构造比二叉查找树要复杂,需要考虑的东西很多,如散列函数的设计,冲突解决办法,扩容,缩容等。而平衡二叉树只需要考虑平衡性这个一个问题,且这个问题的解决方案比较成熟,固定。
同时,为了避免过多的散列冲突,散列表的装载因子不能太大,特别是基于开放寻址法解决冲突的散列表,不然会浪费一定的存储空间。

3、 一些代码搜集+整理

完整的二叉查找树(C语言),代码来自网络

#include <stdio.h>
#include <stdlib.h>

/* A basic unbalanced binary search tree implementation in C, with the following functionalities implemented:
 - Insertion
 - Deletion
 - Search by key value
 - Listing of node keys in order of value (from left to right)
*/

// Node, the basic data structure in the tree
typedef struct node{

    // left child
    struct node* left;

    // right child
    struct node* right;

    // data of the node
    int data;
} node;

// The node constructor, which receives the key value input and returns a node pointer
node* newNode(int data){

    // creates a slug
    node* tmp = (node*)malloc(sizeof(node));

    // initializes the slug
    tmp->data = data;
    tmp->left = NULL;
    tmp->right = NULL;

    return tmp;
}

// Insertion procedure, which inserts the input key in a new node in the tree
node* insert(node* root, int data){
    // If the root of the subtree is null, insert key here
    if (root == NULL)
        root = newNode(data);
    // If it isn't null and the input key is greater than the root key, insert in the right leaf
    else if (data > root->data)
        root->right = insert(root->right, data);
    // If it isn't null and the input key is lower than the root key, insert in the left leaf
    else if (data < root->data)
        root->left = insert(root->left, data);
    // Returns the modified tree
    return root;
}

// Utilitary procedure to find the greatest key in the left subtree
node* getMax(node* root){
    // If there's no leaf to the right, then this is the maximum key value
    if (root->right == NULL)
        return root;
    else
        root->right = getMax(root->right);
}

// Deletion procedure, which searches for the input key in the tree and removes it if present
node* delete(node* root, int data){
    // If the root is null, nothing to be done
    if (root == NULL)
        return root;
    // If the input key is greater than the root's, search in the right subtree
    else if (data > root->data)
        root->right = delete(root->right, data);
    // If the input key is lower than the root's, search in the left subtree
    else if (data < root->data)
        root->left = delete(root->left, data);
    // If the input key matches the root's, check the following cases
    // termination condition
    else if (data == root->data){
        // Case 1: the root has no leaves, remove the node
        if ((root->left == NULL) && (root->right == NULL)){
            free(root);
            return NULL;
        }
        // Case 2: the root has one leaf, make the leaf the new root and remove the old root
        else if (root->left == NULL){
            node* tmp = root;
            root = root->right;
            free(tmp);
            return root;
        }
        else if (root->right == NULL){
            node* tmp = root;
            root = root->left;
            free(tmp);
            return root;
        }
        // Case 3: the root has 2 leaves, find the greatest key in the left subtree and switch with the root's
        else {

            // finds the biggest node in the left branch.
            node* tmp = getMax(root->left);

            // sets the data of this node equal to the data of the biggest node (lefts)
            root->data = tmp->data;
            root->left = delete(root->left, tmp->data);
        }
    }
    return root;
}

// Search procedure, which looks for the input key in the tree and returns 1 if it's present or 0 if it's not in the tree
int find(node* root, int data){
    // If the root is null, the key's not present
    if (root == NULL)
        return 0;
    // If the input key is greater than the root's, search in the right subtree
    else if (data > root->data)
        return find(root->right, data);
    // If the input key is lower than the root's, search in the left subtree
    else if (data < root->data)
        return find(root->left, data);
    // If the input and the root key match, return 1
    else if (data == root->data)
        return 1;
}

// Utilitary procedure to measure the height of the binary tree
int height(node* root){
    // If the root is null, this is the bottom of the tree (height 0)
    if (root == NULL)
        return 0;
    else{
        // Get the height from both left and right subtrees to check which is the greatest
        int right_h = height(root->right);
        int left_h = height(root->left);

        // The final height is the height of the greatest subtree(left or right) plus 1(which is the root's level)
        if (right_h > left_h)
            return (right_h + 1);
        else
            return (left_h + 1);
    }
}

// Utilitary procedure to free all nodes in a tree
void purge(node* root){
    if (root != NULL){
        if (root->left != NULL)
            purge(root->left);
        if (root->right != NULL)
            purge(root->right);
        free(root);
    }
}

// Traversal procedure to list the current keys in the tree in order of value (from the left to the right)
void inOrder(node* root){
    if(root != NULL){
        inOrder(root->left);
        printf("\t[ %d ]\t", root->data);
        inOrder(root->right);
    }
}

void main(){

    // this reference don't change.
    // only the tree changes.
    node* root = NULL;
    int opt = -1;
    int data = 0;

    // event-loop.
    while (opt != 0){
        printf("\n\n[1] Insert Node\n[2] Delete Node\n[3] Find a Node\n[4] Get current Height\n[5] Print Tree in Crescent Order\n[0] Quit\n");
        scanf("%d",&opt); // reads the choice of the user

        // processes the choice
        switch(opt){
            case 1: printf("Enter the new node's value:\n");
                scanf("%d",&data);
                root = insert(root,data);
                break;

            case 2: printf("Enter the value to be removed:\n");
                if (root != NULL){
                    scanf("%d",&data);
                    root = delete(root,data);
                }
                else
                    printf("Tree is already empty!\n");
                break;

            case 3: printf("Enter the searched value:\n");
                scanf("%d",&data);
                find(root,data) ? printf("The value is in the tree.\n") : printf("The value is not in the tree.\n");
                break;

            case 4: printf("Current height of the tree is: %d\n", height(root));
                break;

            case 5: inOrder(root);
                break;
        }
    }

    // deletes the tree from the heap.
    purge(root);
}

二叉树的层次遍历(C语言):

#include<stdio.h>
#include<malloc.h>

#define MaxSize 1024

typedef struct Node{                        //定义二叉链
    struct Node *lchild;                    //指向左孩子节点
    char data;                              //数据元素
    struct Node *rchild;                    //指向右孩子节点 
}BTNode;                                    //struct Node 的别名                        

typedef struct Quene{                       //定义顺序队 
    int front;                              //队头指针 
    BTNode *data[MaxSize];                  //存放队中元素 
    int rear;                               //队尾指针 
}SqQueue;                                   //struct Queue 的别名 

//初始化队列 
void initQueue(SqQueue * &q){
    q=(SqQueue *)malloc(sizeof(SqQueue));   //分配一个空间 
    q->front=q->rear=-1;                    //置 -1 
}

//判断队列是否为空
bool emptyQueue(SqQueue * &q){
    if(q->front==q->rear){                  //首指针和尾指针相等,说明为空 
        return true;                        //返回真 
    }
    else{
        return false;                       //返回假 
    }
}

//进队列
bool enQueue(SqQueue * &q,BTNode * &BT){
    if(q->rear==MaxSize-1){                 //判断队列是否满了 
        return false;                       //返回假 
    }
    q->rear++;                              //头指针加 1 
    q->data[q->rear]=BT;                    //传值 
    return true;                            //返回真 
}

//出队列 
bool deQueue(SqQueue * &q,BTNode * &BT){
    if(q->front==q->rear){                  //判断是否空了 
        return false;                       //返回假 
    }
    q->front++;                             //尾指针加 1 
    BT=q->data[q->front];                   //取值 
    return true;                            //返回真 
}

//创建二叉树 
int createBTNode(BTNode * &BT,char *str,int n){ 
    char ch=str[n];                             //把第 n 个字符赋给ch,方便后面判断 
    n=n+1;
    if(ch!='\0'){                               //如果 ch 不等于结束符就继续创建,否则就结束 
        if( ch=='#'){                           //以 # 号代表 NULL,下面没有了 
            BT = NULL;
        }
        else{
            BT = new BTNode;                    //新建一个二叉链 
            BT->data=ch;                        //把字符存入二叉链 
            n=createBTNode(BT->lchild,str,n);   //左递归创建 
            n=createBTNode(BT->rchild,str,n);   //右递归创建 
        }
    }
    return n;                                   //返回 n,记录字符串使用到哪里了 
}

//先序遍历
void preOrder(BTNode * &BT){
    if(BT!=NULL){                               //判断不为空 
        printf("%c",BT->data);                  //访问根节点
        preOrder(BT->lchild);                   //递归,先序遍历左子树 
        preOrder(BT->rchild);                   //递归,先序遍历右子树 
    }
}

//中序遍历
void inOrder(BTNode * &BT){
    if(BT!=NULL){
        inOrder(BT->lchild);
        printf("%c",BT->data);
        inOrder(BT->rchild);
    }
}

//后序遍历
void postOrder(BTNode * &BT){
    if(BT!=NULL){
        postOrder(BT->lchild);
        postOrder(BT->rchild);
        printf("%c",BT->data);
    }
}

//层次遍历 
void levelOrder(BTNode * &BT){
    SqQueue *q;                                 //定义队列 
    initQueue(q);                               //初始化队列 
    if(BT!=NULL){
        enQueue(q,BT);                          //根节点指针进队列 
    } 
    while(emptyQueue(q)!=true){                 //队不为空循环 
        deQueue(q,BT);                          //出队时的节点 
        printf("%c",BT->data);                  //输出节点存储的值 
        if(BT->lchild!=NULL){                   //有左孩子时将该节点进队列 
            enQueue(q,BT->lchild);
        }
        if(BT->rchild!=NULL){                   //有右孩子时将该节点进队列 
            enQueue(q,BT->rchild);
        }                                       //一层一层的把节点存入队列 
    }                                           //当没有孩子节点时就不再循环 
} 


int main(){
    
    //例子:ABDH###E##CF##G##
    BTNode *BT;
    printf("输入字符串:");
    char *str=(char *)malloc(sizeof(char) * 1024);
    scanf("%s",str); 
    createBTNode(BT,str,0);
    printf("二叉树建立成功\n");
    
    printf("先序遍历结果:");
    preOrder(BT);
    printf("\n");
    
    printf("中序遍历结果:");
    inOrder(BT);
    printf("\n");
    
    printf("后序遍历结果:");
    postOrder(BT);
    printf("\n");

    printf("层序遍历结果:");
    levelOrder(BT);
    printf("\n");
    
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define TElemType char//宏定义,结点中数据域的类型
//枚举,Link为0,Thread为1
typedef enum {
    Link,
    Thread
}PointerTag;
//结点结构构造
typedef struct BiThrNode{
    TElemType data;//数据域
    struct BiThrNode* lchild,*rchild;//左孩子,右孩子指针域
    PointerTag Ltag,Rtag;//标志域,枚举类型
}BiThrNode,*BiThrTree;

BiThrTree pre=NULL;

//采用前序初始化二叉树
//中序和后序只需改变赋值语句的位置即可
void CreateTree(BiThrTree * tree){
    char data;
    scanf("%c",&data);
    if (data!='#'){
        if (!((*tree)=(BiThrNode*)malloc(sizeof(BiThrNode)))){
            printf("申请结点空间失败");
            return;
        }else{
            (*tree)->data=data;//采用前序遍历方式初始化二叉树
            CreateTree(&((*tree)->lchild));//初始化左子树
            CreateTree(&((*tree)->rchild));//初始化右子树
        }
    }else{
        *tree=NULL;
    }
}
//中序对二叉树进行线索化
void InThreading(BiThrTree p){
    //如果当前结点存在
    if (p) {
        InThreading(p->lchild);//递归当前结点的左子树,进行线索化
        //如果当前结点没有左孩子,左标志位设为1,左指针域指向上一结点 pre
        if (!p->lchild) {
            p->Ltag=Thread;
            p->lchild=pre;
        }
        //如果 pre 没有右孩子,右标志位设为 1,右指针域指向当前结点。
        if (pre&&!pre->rchild) {
            pre->Rtag=Thread;
            pre->rchild=p;
        }
        pre=p;//pre指向当前结点
        InThreading(p->rchild);//递归右子树进行线索化
    }
}
//中序遍历线索二叉树
void InOrderThraverse_Thr(BiThrTree p)
{
    while(p)
    {
        //一直找左孩子,最后一个为中序序列中排第一的
        while(p->Ltag == Link){
            p = p->lchild;
        }
        printf("%c ", p->data);  //操作结点数据
        //当结点右标志位为1时,直接找到其后继结点
        while(p->Rtag == Thread && p->rchild !=NULL)
        {
            p = p->rchild;
            printf("%c ", p->data);
        }
        //否则,按照中序遍历的规律,找其右子树中最左下的结点,也就是继续循环遍历
        p = p->rchild;
    }
}

int main() {
    BiThrTree t;
    printf("输入前序二叉树:\n");
    CreateTree(&t);
    InThreading(t);
    printf("输出中序序列:\n");
    InOrderThraverse_Thr(t);
    return 0;
}
树的遍历的python实现
"""
This is pure Python implementation of tree traversal algorithms
"""
import queue
from typing import List


class TreeNode:
    def __init__(self, data):
        self.data = data
        self.right = None
        self.left = None


def build_tree():
    print("\n********Press N to stop entering at any point of time********\n")
    check = input("Enter the value of the root node: ").strip().lower() or "n"
    if check == "n":
        return None
    q: queue.Queue = queue.Queue()
    tree_node = TreeNode(int(check))
    q.put(tree_node)
    while not q.empty():
        node_found = q.get()
        msg = "Enter the left node of %s: " % node_found.data
        check = input(msg).strip().lower() or "n"
        if check == "n":
            return tree_node
        left_node = TreeNode(int(check))
        node_found.left = left_node
        q.put(left_node)
        msg = "Enter the right node of %s: " % node_found.data
        check = input(msg).strip().lower() or "n"
        if check == "n":
            return tree_node
        right_node = TreeNode(int(check))
        node_found.right = right_node
        q.put(right_node)


def pre_order(node: TreeNode) -> None:
    """
    >>> root = TreeNode(1)
    >>> tree_node2 = TreeNode(2)
    >>> tree_node3 = TreeNode(3)
    >>> tree_node4 = TreeNode(4)
    >>> tree_node5 = TreeNode(5)
    >>> tree_node6 = TreeNode(6)
    >>> tree_node7 = TreeNode(7)
    >>> root.left, root.right = tree_node2, tree_node3
    >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5
    >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7
    >>> pre_order(root)
    1 2 4 5 3 6 7 
    """
    if not isinstance(node, TreeNode) or not node:
        return
    print(node.data, end=" ")
    pre_order(node.left)
    pre_order(node.right)


def in_order(node: TreeNode) -> None:
    """
    >>> root = TreeNode(1)
    >>> tree_node2 = TreeNode(2)
    >>> tree_node3 = TreeNode(3)
    >>> tree_node4 = TreeNode(4)
    >>> tree_node5 = TreeNode(5)
    >>> tree_node6 = TreeNode(6)
    >>> tree_node7 = TreeNode(7)
    >>> root.left, root.right = tree_node2, tree_node3
    >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5
    >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7
    >>> in_order(root)
    4 2 5 1 6 3 7 
    """
    if not isinstance(node, TreeNode) or not node:
        return
    in_order(node.left)
    print(node.data, end=" ")
    in_order(node.right)


def post_order(node: TreeNode) -> None:
    """
    >>> root = TreeNode(1)
    >>> tree_node2 = TreeNode(2)
    >>> tree_node3 = TreeNode(3)
    >>> tree_node4 = TreeNode(4)
    >>> tree_node5 = TreeNode(5)
    >>> tree_node6 = TreeNode(6)
    >>> tree_node7 = TreeNode(7)
    >>> root.left, root.right = tree_node2, tree_node3
    >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5
    >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7
    >>> post_order(root)
    4 5 2 6 7 3 1 
    """
    if not isinstance(node, TreeNode) or not node:
        return
    post_order(node.left)
    post_order(node.right)
    print(node.data, end=" ")


def level_order(node: TreeNode) -> None:
    """
    >>> root = TreeNode(1)
    >>> tree_node2 = TreeNode(2)
    >>> tree_node3 = TreeNode(3)
    >>> tree_node4 = TreeNode(4)
    >>> tree_node5 = TreeNode(5)
    >>> tree_node6 = TreeNode(6)
    >>> tree_node7 = TreeNode(7)
    >>> root.left, root.right = tree_node2, tree_node3
    >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5
    >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7
    >>> level_order(root)
    1 2 3 4 5 6 7 
    """
    if not isinstance(node, TreeNode) or not node:
        return
    q: queue.Queue = queue.Queue()
    q.put(node)
    while not q.empty():
        node_dequeued = q.get()
        print(node_dequeued.data, end=" ")
        if node_dequeued.left:
            q.put(node_dequeued.left)
        if node_dequeued.right:
            q.put(node_dequeued.right)


def level_order_actual(node: TreeNode) -> None:
    """
    >>> root = TreeNode(1)
    >>> tree_node2 = TreeNode(2)
    >>> tree_node3 = TreeNode(3)
    >>> tree_node4 = TreeNode(4)
    >>> tree_node5 = TreeNode(5)
    >>> tree_node6 = TreeNode(6)
    >>> tree_node7 = TreeNode(7)
    >>> root.left, root.right = tree_node2, tree_node3
    >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5
    >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7
    >>> level_order_actual(root)
    1 
    2 3 
    4 5 6 7 
    """
    if not isinstance(node, TreeNode) or not node:
        return
    q: queue.Queue = queue.Queue()
    q.put(node)
    while not q.empty():
        list = []
        while not q.empty():
            node_dequeued = q.get()
            print(node_dequeued.data, end=" ")
            if node_dequeued.left:
                list.append(node_dequeued.left)
            if node_dequeued.right:
                list.append(node_dequeued.right)
        print()
        for node in list:
            q.put(node)


# iteration version
def pre_order_iter(node: TreeNode) -> None:
    """
    >>> root = TreeNode(1)
    >>> tree_node2 = TreeNode(2)
    >>> tree_node3 = TreeNode(3)
    >>> tree_node4 = TreeNode(4)
    >>> tree_node5 = TreeNode(5)
    >>> tree_node6 = TreeNode(6)
    >>> tree_node7 = TreeNode(7)
    >>> root.left, root.right = tree_node2, tree_node3
    >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5
    >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7
    >>> pre_order_iter(root)
    1 2 4 5 3 6 7 
    """
    if not isinstance(node, TreeNode) or not node:
        return
    stack: List[TreeNode] = []
    n = node
    while n or stack:
        while n:  # start from root node, find its left child
            print(n.data, end=" ")
            stack.append(n)
            n = n.left
        # end of while means current node doesn't have left child
        n = stack.pop()
        # start to traverse its right child
        n = n.right


def in_order_iter(node: TreeNode) -> None:
    """
    >>> root = TreeNode(1)
    >>> tree_node2 = TreeNode(2)
    >>> tree_node3 = TreeNode(3)
    >>> tree_node4 = TreeNode(4)
    >>> tree_node5 = TreeNode(5)
    >>> tree_node6 = TreeNode(6)
    >>> tree_node7 = TreeNode(7)
    >>> root.left, root.right = tree_node2, tree_node3
    >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5
    >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7
    >>> in_order_iter(root)
    4 2 5 1 6 3 7 
    """
    if not isinstance(node, TreeNode) or not node:
        return
    stack: List[TreeNode] = []
    n = node
    while n or stack:
        while n:
            stack.append(n)
            n = n.left
        n = stack.pop()
        print(n.data, end=" ")
        n = n.right


def post_order_iter(node: TreeNode) -> None:
    """
    >>> root = TreeNode(1)
    >>> tree_node2 = TreeNode(2)
    >>> tree_node3 = TreeNode(3)
    >>> tree_node4 = TreeNode(4)
    >>> tree_node5 = TreeNode(5)
    >>> tree_node6 = TreeNode(6)
    >>> tree_node7 = TreeNode(7)
    >>> root.left, root.right = tree_node2, tree_node3
    >>> tree_node2.left, tree_node2.right = tree_node4 , tree_node5
    >>> tree_node3.left, tree_node3.right = tree_node6 , tree_node7
    >>> post_order_iter(root)
    4 5 2 6 7 3 1 
    """
    if not isinstance(node, TreeNode) or not node:
        return
    stack1, stack2 = [], []
    n = node
    stack1.append(n)
    while stack1:  # to find the reversed order of post order, store it in stack2
        n = stack1.pop()
        if n.left:
            stack1.append(n.left)
        if n.right:
            stack1.append(n.right)
        stack2.append(n)
    while stack2:  # pop up from stack2 will be the post order
        print(stack2.pop().data, end=" ")


def prompt(s: str = "", width=50, char="*") -> str:
    if not s:
        return "\n" + width * char
    left, extra = divmod(width - len(s) - 2, 2)
    return f"{left * char} {s} {(left + extra) * char}"


if __name__ == "__main__":
    import doctest

    doctest.testmod()
    print(prompt("Binary Tree Traversals"))

    node = build_tree()
    print(prompt("Pre Order Traversal"))
    pre_order(node)
    print(prompt() + "\n")

    print(prompt("In Order Traversal"))
    in_order(node)
    print(prompt() + "\n")

    print(prompt("Post Order Traversal"))
    post_order(node)
    print(prompt() + "\n")

    print(prompt("Level Order Traversal"))
    level_order(node)
    print(prompt() + "\n")

    print(prompt("Actual Level Order Traversal"))
    level_order_actual(node)
    print("*" * 50 + "\n")

    print(prompt("Pre Order Traversal - Iteration Version"))
    pre_order_iter(node)
    print(prompt() + "\n")

    print(prompt("In Order Traversal - Iteration Version"))
    in_order_iter(node)
    print(prompt() + "\n")

    print(prompt("Post Order Traversal - Iteration Version"))
    post_order_iter(node)
    print(prompt())

平衡二叉树的python实现

"""
An auto-balanced binary tree!
"""
import math
import random


class my_queue:
    def __init__(self):
        self.data = []
        self.head = 0
        self.tail = 0

    def isEmpty(self):
        return self.head == self.tail

    def push(self, data):
        self.data.append(data)
        self.tail = self.tail + 1

    def pop(self):
        ret = self.data[self.head]
        self.head = self.head + 1
        return ret

    def count(self):
        return self.tail - self.head

    def print(self):
        print(self.data)
        print("**************")
        print(self.data[self.head : self.tail])


class my_node:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None
        self.height = 1

    def getdata(self):
        return self.data

    def getleft(self):
        return self.left

    def getright(self):
        return self.right

    def getheight(self):
        return self.height

    def setdata(self, data):
        self.data = data
        return

    def setleft(self, node):
        self.left = node
        return

    def setright(self, node):
        self.right = node
        return

    def setheight(self, height):
        self.height = height
        return


def getheight(node):
    if node is None:
        return 0
    return node.getheight()


def my_max(a, b):
    if a > b:
        return a
    return b


def leftrotation(node):
    r"""
            A                      B
           / \                    / \
          B   C                  Bl  A
         / \       -->          /   / \
        Bl  Br                 UB Br  C
       /
     UB
  
    UB = unbalanced node  
    """
    print("left rotation node:", node.getdata())
    ret = node.getleft()
    node.setleft(ret.getright())
    ret.setright(node)
    h1 = my_max(getheight(node.getright()), getheight(node.getleft())) + 1
    node.setheight(h1)
    h2 = my_max(getheight(ret.getright()), getheight(ret.getleft())) + 1
    ret.setheight(h2)
    return ret


def rightrotation(node):
    """
        a mirror symmetry rotation of the leftrotation
    """
    print("right rotation node:", node.getdata())
    ret = node.getright()
    node.setright(ret.getleft())
    ret.setleft(node)
    h1 = my_max(getheight(node.getright()), getheight(node.getleft())) + 1
    node.setheight(h1)
    h2 = my_max(getheight(ret.getright()), getheight(ret.getleft())) + 1
    ret.setheight(h2)
    return ret


def rlrotation(node):
    r"""
            A              A                    Br      
           / \            / \                  /  \
          B   C    RR    Br  C       LR       B    A
         / \       -->  /  \         -->    /     / \
        Bl  Br         B   UB              Bl    UB  C  
             \        /
             UB     Bl
    RR = rightrotation   LR = leftrotation
    """
    node.setleft(rightrotation(node.getleft()))
    return leftrotation(node)


def lrrotation(node):
    node.setright(leftrotation(node.getright()))
    return rightrotation(node)


def insert_node(node, data):
    if node is None:
        return my_node(data)
    if data < node.getdata():
        node.setleft(insert_node(node.getleft(), data))
        if (
            getheight(node.getleft()) - getheight(node.getright()) == 2
        ):  # an unbalance detected
            if (
                data < node.getleft().getdata()
            ):  # new node is the left child of the left child
                node = leftrotation(node)
            else:
                node = rlrotation(node)  # new node is the right child of the left child
    else:
        node.setright(insert_node(node.getright(), data))
        if getheight(node.getright()) - getheight(node.getleft()) == 2:
            if data < node.getright().getdata():
                node = lrrotation(node)
            else:
                node = rightrotation(node)
    h1 = my_max(getheight(node.getright()), getheight(node.getleft())) + 1
    node.setheight(h1)
    return node


def getRightMost(root):
    while root.getright() is not None:
        root = root.getright()
    return root.getdata()


def getLeftMost(root):
    while root.getleft() is not None:
        root = root.getleft()
    return root.getdata()


def del_node(root, data):
    if root.getdata() == data:
        if root.getleft() is not None and root.getright() is not None:
            temp_data = getLeftMost(root.getright())
            root.setdata(temp_data)
            root.setright(del_node(root.getright(), temp_data))
        elif root.getleft() is not None:
            root = root.getleft()
        else:
            root = root.getright()
    elif root.getdata() > data:
        if root.getleft() is None:
            print("No such data")
            return root
        else:
            root.setleft(del_node(root.getleft(), data))
    elif root.getdata() < data:
        if root.getright() is None:
            return root
        else:
            root.setright(del_node(root.getright(), data))
    if root is None:
        return root
    if getheight(root.getright()) - getheight(root.getleft()) == 2:
        if getheight(root.getright().getright()) > getheight(root.getright().getleft()):
            root = rightrotation(root)
        else:
            root = lrrotation(root)
    elif getheight(root.getright()) - getheight(root.getleft()) == -2:
        if getheight(root.getleft().getleft()) > getheight(root.getleft().getright()):
            root = leftrotation(root)
        else:
            root = rlrotation(root)
    height = my_max(getheight(root.getright()), getheight(root.getleft())) + 1
    root.setheight(height)
    return root


class AVLtree:
    def __init__(self):
        self.root = None

    def getheight(self):
        #        print("yyy")
        return getheight(self.root)

    def insert(self, data):
        print("insert:" + str(data))
        self.root = insert_node(self.root, data)

    def del_node(self, data):
        print("delete:" + str(data))
        if self.root is None:
            print("Tree is empty!")
            return
        self.root = del_node(self.root, data)

    def traversale(self):  # a level traversale, gives a more intuitive look on the tree
        q = my_queue()
        q.push(self.root)
        layer = self.getheight()
        if layer == 0:
            return
        cnt = 0
        while not q.isEmpty():
            node = q.pop()
            space = " " * int(math.pow(2, layer - 1))
            print(space, end="")
            if node is None:
                print("*", end="")
                q.push(None)
                q.push(None)
            else:
                print(node.getdata(), end="")
                q.push(node.getleft())
                q.push(node.getright())
            print(space, end="")
            cnt = cnt + 1
            for i in range(100):
                if cnt == math.pow(2, i) - 1:
                    layer = layer - 1
                    if layer == 0:
                        print()
                        print("*************************************")
                        return
                    print()
                    break
        print()
        print("*************************************")
        return

    def test(self):
        getheight(None)
        print("****")
        self.getheight()


if __name__ == "__main__":
    t = AVLtree()
    t.traversale()
    l = list(range(10))
    random.shuffle(l)
    for i in l:
        t.insert(i)
        t.traversale()

    random.shuffle(l)
    for i in l:
        t.del_node(i)
        t.traversale()

二叉树python实现:

class Node:  # This is the Class Node with a constructor that contains data variable to type data and left, right pointers.
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None


def display(tree):  # In Order traversal of the tree

    if tree is None:
        return

    if tree.left is not None:
        display(tree.left)

    print(tree.data)

    if tree.right is not None:
        display(tree.right)

    return


def depth_of_tree(
    tree,
):  # This is the recursive function to find the depth of binary tree.
    if tree is None:
        return 0
    else:
        depth_l_tree = depth_of_tree(tree.left)
        depth_r_tree = depth_of_tree(tree.right)
        if depth_l_tree > depth_r_tree:
            return 1 + depth_l_tree
        else:
            return 1 + depth_r_tree


def is_full_binary_tree(
    tree,
):  # This function returns that is it full binary tree or not?
    if tree is None:
        return True
    if (tree.left is None) and (tree.right is None):
        return True
    if (tree.left is not None) and (tree.right is not None):
        return is_full_binary_tree(tree.left) and is_full_binary_tree(tree.right)
    else:
        return False


def main():  # Main function for testing.
    tree = Node(1)
    tree.left = Node(2)
    tree.right = Node(3)
    tree.left.left = Node(4)
    tree.left.right = Node(5)
    tree.left.right.left = Node(6)
    tree.right.left = Node(7)
    tree.right.left.left = Node(8)
    tree.right.left.left.right = Node(9)

    print(is_full_binary_tree(tree))
    print(depth_of_tree(tree))
    print("Tree is: ")
    display(tree)


if __name__ == "__main__":
    main()

二叉查找树的python实现:

"""
A binary search Tree
"""


class Node:
    def __init__(self, value, parent):
        self.value = value
        self.parent = parent  # Added in order to delete a node easier
        self.left = None
        self.right = None

    def __repr__(self):
        from pprint import pformat

        if self.left is None and self.right is None:
            return str(self.value)
        return pformat({"%s" % (self.value): (self.left, self.right)}, indent=1)


class BinarySearchTree:
    def __init__(self, root=None):
        self.root = root

    def __str__(self):
        """
        Return a string of all the Nodes using in order traversal
        """
        return str(self.root)

    def __reassign_nodes(self, node, new_children):
        if new_children is not None:  # reset its kids
            new_children.parent = node.parent
        if node.parent is not None:  # reset its parent
            if self.is_right(node):  # If it is the right children
                node.parent.right = new_children
            else:
                node.parent.left = new_children
        else:
            self.root = new_children

    def is_right(self, node):
        return node == node.parent.right

    def empty(self):
        return self.root is None

    def __insert(self, value):
        """
        Insert a new node in Binary Search Tree with value label
        """
        new_node = Node(value, None)  # create a new Node
        if self.empty():  # if Tree is empty
            self.root = new_node  # set its root
        else:  # Tree is not empty
            parent_node = self.root  # from root
            while True:  # While we don't get to a leaf
                if value < parent_node.value:  # We go left
                    if parent_node.left is None:
                        parent_node.left = new_node  # We insert the new node in a leaf
                        break
                    else:
                        parent_node = parent_node.left
                else:
                    if parent_node.right is None:
                        parent_node.right = new_node
                        break
                    else:
                        parent_node = parent_node.right
            new_node.parent = parent_node

    def insert(self, *values):
        for value in values:
            self.__insert(value)
        return self

    def search(self, value):
        if self.empty():
            raise IndexError("Warning: Tree is empty! please use another.")
        else:
            node = self.root
            # use lazy evaluation here to avoid NoneType Attribute error
            while node is not None and node.value is not value:
                node = node.left if value < node.value else node.right
            return node

    def get_max(self, node=None):
        """
        We go deep on the right branch
        """
        if node is None:
            node = self.root
        if not self.empty():
            while node.right is not None:
                node = node.right
        return node

    def get_min(self, node=None):
        """
        We go deep on the left branch
        """
        if node is None:
            node = self.root
        if not self.empty():
            node = self.root
            while node.left is not None:
                node = node.left
        return node

    def remove(self, value):
        node = self.search(value)  # Look for the node with that label
        if node is not None:
            if node.left is None and node.right is None:  # If it has no children
                self.__reassign_nodes(node, None)
            elif node.left is None:  # Has only right children
                self.__reassign_nodes(node, node.right)
            elif node.right is None:  # Has only left children
                self.__reassign_nodes(node, node.left)
            else:
                tmp_node = self.get_max(
                    node.left
                )  # Gets the max value of the left branch
                self.remove(tmp_node.value)
                node.value = (
                    tmp_node.value
                )  # Assigns the value to the node to delete and keep tree structure

    def preorder_traverse(self, node):
        if node is not None:
            yield node  # Preorder Traversal
            yield from self.preorder_traverse(node.left)
            yield from self.preorder_traverse(node.right)

    def traversal_tree(self, traversal_function=None):
        """
        This function traversal the tree.
        You can pass a function to traversal the tree as needed by client code
        """
        if traversal_function is None:
            return self.preorder_traverse(self.root)
        else:
            return traversal_function(self.root)


def postorder(curr_node):
    """
    postOrder (left, right, self)
    """
    node_list = list()
    if curr_node is not None:
        node_list = postorder(curr_node.left) + postorder(curr_node.right) + [curr_node]
    return node_list


def binary_search_tree():
    """
    Example
                  8
                 / \
                3   10
               / \    \
              1   6    14
                 / \   /
                4   7 13

    >>> t = BinarySearchTree().insert(8, 3, 6, 1, 10, 14, 13, 4, 7)
    >>> print(" ".join(repr(i.value) for i in t.traversal_tree()))
    8 3 1 6 4 7 10 14 13
    >>> print(" ".join(repr(i.value) for i in t.traversal_tree(postorder)))
    1 4 7 6 3 13 14 10 8
    >>> BinarySearchTree().search(6)
    Traceback (most recent call last):
    ...
    IndexError: Warning: Tree is empty! please use another.
    """
    testlist = (8, 3, 6, 1, 10, 14, 13, 4, 7)
    t = BinarySearchTree()
    for i in testlist:
        t.insert(i)

    # Prints all the elements of the list in order traversal
    print(t)

    if t.search(6) is not None:
        print("The value 6 exists")
    else:
        print("The value 6 doesn't exist")

    if t.search(-1) is not None:
        print("The value -1 exists")
    else:
        print("The value -1 doesn't exist")

    if not t.empty():
        print("Max Value: ", t.get_max().value)
        print("Min Value: ", t.get_min().value)

    for i in testlist:
        t.remove(i)
        print(t)


if __name__ == "__main__":
    import doctest

    doctest.testmod()
    # binary_search_tree()


作者:安东尼_Anthony
链接:https://www.jianshu.com/p/2aaaae9392d3