!!版权声明:本文为博主原创文章,版权归原文作者和博客园共有,谢绝任何形式的 转载!!

作者:mohist

--- 欢迎指正---

二叉树特点:

 要么为空树;要么,当前结点的左孩子比当前结点值小,当前结点的右孩子比当前结点的值大。

1、插入:

  1.1 插入结点的值比当前结点的值小,继续找当前结点的左子树,

  1.2 插入结点的值比当前结点的值大,继续找当前结点的右子树,

  1.3 找到合适的位置了,插入树。

2、删除:

  2.1 删除结点是叶子结点,直接将其删除即可

  2.2 删除结点只有左孩子或者只有右孩子,将其孩子结点删除,并将指向孩子结点的分支设置为空,c++是设置为NULL。不过更好的做法是,将孩子结点的值替换到当前结点,再删除孩子结点即可。

  2.3 删除的结点同时含有左孩子与右孩子,需要找到删除结点的后继结点,将后继结点作为当前结点。

完整源码:

#include <iostream>
using namespace std; struct node
{
// 数据域
int data; // 左节点
node *lc; // 右结点
node *rc; // 构造函数
node()
: data(0)
, lc(NULL)
, rc(NULL)
{
}
}; // bst
class bstree
{
public:
enum
{
hmax_size_32767 = 32767,
hmin_size_0 = 0,
}; public: // 构造函数
bstree()
: root(NULL)
, size(0)
{
} // 析构函数
virtual ~bstree(){} int get_size()
{
return size;
} // 插入结点
void insert_node(int data)
{
int cur_size = get_size();
if (hmax_size_32767 == cur_size)
{
cout << "insert node error, the size of the tree is max" << endl;
return ;
}
root = insert(root, data);
} // 先序遍历(前序遍历)
void pre_order()
{
pre_order_traverse(root);
} // 中序遍历
void in_order()
{
in_order_traverse(root);
} // 后序遍历
void post_order()
{
post_order_traverse(root);
} /*
查找某个结点
int key - 查找结果 返回值:
NULL : 可能为root为空 或者 没有找到
!= NULL, 找到结点
*/
node* query(int key)
{
if (NULL == root)
{
cout << "query error, root = null" << endl;
return NULL;
} return query_node(root, key);
} // 删除树
void remove_all()
{
if (NULL == root)
{
cout << "remove all failed, root = null" << endl;
return;
} remove_all(root); int cur_size = get_size();
if (0 == cur_size)
root = NULL;
} // 删除某个结点
void remove_node(int del_data)
{
if (NULL == root)
{
cout << "remove node error, root = null" << endl;
return;
} node *parent_node = NULL;
node *del_node = root; // 找到删除结点的父节点与删除结点
while (del_node)
{
if (del_data == del_node->data)
break;
else if (del_data > del_node->data)
{
parent_node = del_node;
del_node = del_node->rc;
}
else if (del_data < del_node->data)
{
parent_node = del_node;
del_node = del_node->lc;
}
} // 若没有找到要删除的结点
if (NULL == del_node)
{
cout << "remove node error, " << del_data << " was not find" << endl;
return;
} // 1、若删除的结点没有左子树和右子树
if ( (NULL == del_node->lc) && (NULL == del_node->rc) )
{
// 为什么要先判断根结点,因为根结点的父节点找不到,结果为NULL,
// 1.1 可能只有一个根结点, 将root释放值为空
if (del_node == root)
{
root = NULL;
delete del_node;
del_node = NULL; dec_size();
return;
} // 1.2 非根结点,那就是叶子结点了, 将父节点指向删除结点的分支指向NULL
if (del_node == parent_node->lc)
parent_node->lc = NULL;
else if (del_node == parent_node->rc)
parent_node->rc = NULL; // 释放结点
delete del_node;
del_node = NULL;
dec_size();
} // 2、若删除结点只有左孩子,没有右孩子
else if ( (NULL != del_node->lc) && (NULL == del_node->rc) )
{
// 2.1 删除结点为根结点,则将删除结点的左孩子替代当前删除结点
if (del_node == root)
{
root = root->lc;
}
// 2.2 其他结点,将删除结点的左孩子作为父节点的左孩子
else
{
if (parent_node->lc == del_node)
parent_node->lc = del_node->lc;
else if (parent_node->rc == del_node)
parent_node->rc = del_node->lc;
} delete del_node;
del_node = NULL; dec_size();
} // 3、若删除结点只有右孩子
else if ( (NULL == del_node->lc) && (NULL != del_node->rc) )
{
// 3.1 若为根结点
if (root == del_node)
{
root = root->rc;
}
else
{
if (del_node == parent_node->lc)
parent_node->lc = del_node->rc;
else if (del_node == parent_node->rc)
parent_node->rc = del_node->rc;
} delete del_node;
del_node = NULL; dec_size();
} // 4、若删除结点既有左孩子,又有右孩子,需要找到删除结点的后继结点作为根结点
else if ( (NULL != del_node->lc) && (NULL != del_node->rc) )
{
node *successor_node = del_node->rc;
parent_node = del_node; while (successor_node->lc)
{
parent_node = successor_node;
successor_node = successor_node->lc;
} // 交换后继结点与当前删除结点的数据域
del_node->data = successor_node->data;
// 将指向后继结点的父节点的孩子设置后继结点的右子树
if (successor_node == parent_node->lc)
parent_node->lc = successor_node->rc;
else if (successor_node == parent_node->rc)
parent_node->rc = successor_node->rc; // 删除后继结点
del_node = successor_node;
delete del_node;
del_node = NULL; dec_size();
}
} // 返回以proot为根结点的最小结点
node *get_min_node(node *proot)
{
if (NULL == proot->lc)
return proot; return get_min_node(proot->lc);
} // 返回以proo为根节点的最大结点
node *get_max_node(node *proot)
{
if (NULL == proot->rc)
return proot; return get_max_node(proot->rc);
} // 返回根节点
node *get_root_node()
{
return root;
} // 返回proot结点的父节点
node *get_parent_node(int key)
{
// 当前结点
node *cur_node = NULL;
// 父节点
node *parent_node = NULL; cur_node = root; // 标记是否找到
bool is_find = false;
while (cur_node)
{
if (key == cur_node->data)
{
is_find = true;
break;
} // 因为比当前结点的值还要小,所以需要查找当前结点的左子树
else if (key < cur_node->data)
{
parent_node = cur_node;
cur_node = cur_node->lc;
}
// 同上, 查找当前结点的右子树
else if (key > cur_node->data)
{
parent_node = cur_node;
cur_node = cur_node->rc;
}
} return (true == is_find)? parent_node : NULL;
} private: //查找某个值
node *query_node(node *proot, int key)
{
if (NULL == proot)
{
return proot;
} if (proot->data == key)
return proot;
else if (proot->data > key)
{
return query_node(proot->lc, key);
}
else if (proot->data < key)
{
return query_node(proot->rc, key);
} return NULL;
} // 后序遍历删除所有结点
void remove_all(node *proot)
{
if (NULL != proot)
{
remove_all(proot->lc);
remove_all(proot->rc);
delete proot; dec_size();
}
} // 先序遍历
void pre_order_traverse(node *proot)
{
if (NULL != proot)
{
cout << proot->data << ", ";
pre_order_traverse(proot->lc);
pre_order_traverse(proot->rc);
}
} // 中序遍历
void in_order_traverse(node *proot)
{
if (NULL != proot)
{
in_order_traverse(proot->lc);
cout << proot->data << ", ";
in_order_traverse(proot->rc);
}
} // 后续遍历
void post_order_traverse(node *proot)
{
if (NULL != proot)
{
post_order_traverse(proot->lc);
post_order_traverse(proot->rc);
cout << proot->data << ", ";
}
} // 插入结点
node *insert(node *proot, int data)
{
// 结点不存在, 则创建
if (NULL == proot)
{
node *new_node = new(std::nothrow) node;
if (NULL != new_node)
{
new_node->data = data;
proot = new_node; // 结点+1;
add_size();
} return proot;
} // 插入值比当前结点值还要小, 则应该插入到当前节点的左边
if (proot->data > data)
{
proot->lc = insert(proot->lc, data);
}
// 插入之比当前结点值还要打,则应该插入到当前结点的右边
else if (proot->data < data)
{
proot->rc = insert(proot->rc, data);
} // 相等,则不插入结点。 return proot;
} // size + 1
void add_size()
{
if (hmax_size_32767 == size)
return ;
size++;
} // size - 1
void dec_size()
{
if ( hmin_size_0 == size)
{
return ;
} size--;
} private:
// 根结点
node *root; // 当前树的结点个数
int size;
}; // 测试代码
int main()
{ bstree tree; //
tree.insert_node(50); tree.insert_node(30);
tree.insert_node(10);
tree.insert_node(0);
tree.insert_node(20);
tree.insert_node(40); tree.insert_node(70);
tree.insert_node(90);
tree.insert_node(100);
tree.insert_node(60);
tree.insert_node(80); // 前序遍历
cout << "前序遍历" << endl;
tree.pre_order();
cout << endl; // 中序遍历
cout << "中序遍历" << endl;
tree.in_order();
cout << endl; // 后序遍历
cout << "后序遍历" << endl;
tree.post_order();
cout << endl; cout << "删除结点开始,结束请输入10086" << endl; int del_key = 0; while (true)
{
cout << "输入删除结点值 = ";
cin >> del_key;
if (10086 == del_key)
break; tree.remove_node(del_key); cout << "删除后,结点个数 = " << tree.get_size() << endl;
cout << "删除后, 中序遍历结果:" ;// << endl;
tree.in_order();
cout << endl << endl;
} tree.remove_all(); return 0;
}

测试结果:

二叉树c++实现的更多相关文章

  1. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  2. 二叉树的递归实现(java)

    这里演示的二叉树为3层. 递归实现,先构造出一个root节点,先判断左子节点是否为空,为空则构造左子节点,否则进入下一步判断右子节点是否为空,为空则构造右子节点. 利用层数控制迭代次数. 依次递归第二 ...

  3. c 二叉树的使用

    简单的通过一个寻找嫌疑人的小程序 来演示二叉树的使用 #include <stdio.h> #include <stdlib.h> #include <string.h& ...

  4. Java 二叉树遍历右视图-LeetCode199

    题目如下: 题目给出的例子不太好,容易让人误解成不断顺着右节点访问就好了,但是题目意思并不是这样. 换成通俗的意思:按层遍历二叉树,输出每层的最右端结点. 这就明白时一道二叉树层序遍历的问题,用一个队 ...

  5. 数据结构:二叉树 基于list实现(python版)

    基于python的list实现二叉树 #!/usr/bin/env python # -*- coding:utf-8 -*- class BinTreeValueError(ValueError): ...

  6. [LeetCode] Path Sum III 二叉树的路径和之三

    You are given a binary tree in which each node contains an integer value. Find the number of paths t ...

  7. [LeetCode] Find Leaves of Binary Tree 找二叉树的叶节点

    Given a binary tree, find all leaves and then remove those leaves. Then repeat the previous steps un ...

  8. [LeetCode] Verify Preorder Serialization of a Binary Tree 验证二叉树的先序序列化

    One way to serialize a binary tree is to use pre-oder traversal. When we encounter a non-null node, ...

  9. [LeetCode] Binary Tree Vertical Order Traversal 二叉树的竖直遍历

    Given a binary tree, return the vertical order traversal of its nodes' values. (ie, from top to bott ...

  10. [LeetCode] Binary Tree Longest Consecutive Sequence 二叉树最长连续序列

    Given a binary tree, find the length of the longest consecutive sequence path. The path refers to an ...

随机推荐

  1. JSOI 2008 最小生成树计数

    JSOI 2008 最小生成树计数 今天的题目终于良心一点辣 一个套路+模版题. 考虑昨天讲的那几个结论,我们有当我们只保留最小生成树中权值不超过 $ k $ 的边的时候形成的联通块是一定的. 我们可 ...

  2. Ubuntu 彻底卸载 MySQL 数据库

    Ubuntu 18.04 彻底卸载MySQL 5.7.31 1. 查看MySQL的依赖项 dpkg --list|grep mysql 2. 卸载 mysql-common sudo apt remo ...

  3. [Ocean Modelling for Begineers] Ch3. Basics of Geophysical Fluid Dynamics

    Ch3. Basics of Geophysical Fluid Dynamics 本章主要介绍 标量与向量 Newton定律 波动与恒定状态流体 浮力 科氏力 守恒律 紊动 N-S方程 3.1 Un ...

  4. Linux中gz文件操作遇到的一些技巧和坑

    目录 不解压情况下获取gz超大文件的前/后几行? Perl读入gz文件操作? 不能直接通过wc -l 来统计gz文件的行数 前提是gz文件超大,如上百G,肯定不能直接解压来做. 不解压情况下获取gz超 ...

  5. NAT 工作原理

    网络地址转换,就是替换IP报文头部的地址信息.NAT通常部署在一个组织的网络出口位置,通过将内部网络IP地址替换为出口的IP地址提供公网可达性和上层协议的连接能力 规定了三个保留地址段落:10.0.0 ...

  6. 关于Stream的使用

    引言 Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找.过滤和映射数据等操作.使用Stream API 对集合数据进行操作,就类似于使用 ...

  7. 学习Java 2021/10/7

    java重写Override 重载Overload 重写是子类对父类的允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变.即外壳不变,核心重写 重写规则: 参数列表与被重写方法的参数列表必须 ...

  8. 学习java 7.21

    学习内容: 模块使用 AWT是窗口框架 它从不同平台的窗口系统中抽取出共同组件,当程序运行时,将这些组件的创建和动作委托给程序所在的运行平台.简而言之,当使用AWT编写图形界面应用时,程序仅指定了界面 ...

  9. 文件和目录之间建立链接 (ln)

  10. Zookeeper【概述、安装、原理、使用】

    目录 第1章 Zookeeper入门 1.1 概述 1.2 特点 1.3 数据结构 1.4应用场景 第2章 Zookeep安装 2.1 下载地址 2.2 本地模式安装 1. 安装前准备 2. 配置修改 ...