c++排序二叉树的出现的私有函数讨论,以及二叉树的删除操作详解
c++排序二叉树的出现的私有函数讨论, 以及二叉树的删除操作详解
标签(空格分隔): c++
前言
我在c++学习的过程中, 最近打了一个排序二叉树的题目,题目中出现了私有函数成员,当时没有理解清楚这样设置的用意,导致题目没有做出来,后来终于想清楚,所以特地写这一篇来分享给大家,同时加深印象。有出错的地方希望给位朋友斧正。
题目
先看题目, 给定二叉树类的声明, 要求写出其定义, 并且要求通过各种例子
二叉树类定义
#ifndef BT_TREE
#define BT_TREE
#include <iostream>
using namespace std;
struct node {
int ele;
node* left;
node* right;
node(int e) :left(0), right(0) {
ele = e;
}
};
class BinaryTree {
private: //注意,这里表示一个树是用一个根节点来表示
node* root; //这棵树,而网上绝大多数都是把node的参数
//放到类的私有变量里,这也决定了
//我们不能用网上的做法来搞
void MemoryDelete(node* p);
static void BuildTree(const node* Source_Root, node* &Target_Root);
static void BuildTree(const int* arr, int len, node* &root);
static void preorder(const node* p);
public:
BinaryTree();
BinaryTree(const BinaryTree&);
BinaryTree(const int* arr, int len);
void ResetTree(const int* arr, int len);
~BinaryTree();
void clear();
void insert(int ele);
void Delete(int ele);
void print();
};
#endif
**总起:
这个题主要理解清楚放到私有成员的static函数用意, static 函数,参数是node* 表示树的根节点,可以在没有对象时调用**这样就决定了我们使用递归的时候利用的就是我们的私有成员函数。
1.私有的 void MemoryDelete(node* p)函数
void BinaryTree::MemoryDelete(node* p) { //用于树的数据删除,被析构函数和clear,reset函数调用。 为什么不在clear和reset函数里写呢?
if (p != NULL) { //因为我需要用递归,而如果我递归clear和reset是不可能成功的,因为我不可能递归作用于对象的函数(也就是
MemoryDelete(p->left); //先要有对象)
MemoryDelete(p->right);
delete p;
p = NULL;
}
}
2.私有的 void BinaryTree::BuildTree(const node* Source_Root, node* &Target_Root) 函数
void BinaryTree::BuildTree(const node* Source_Root, node* &Target_Root) { // static 函数 参数是node* 表示树的根节点, 可以在没有对象时调用
if (Source_Root == NULL) { // 但是这里的递归 你要把参数理解成 每个节点 而不是根节点
Target_Root = NULL;
}
else {
Target_Root = new node(Source_Root->ele);
BuildTree(Source_Root->left, Target_Root->left);
BuildTree(Source_Root->right, Target_Root->right); //相当于对每个节点进行拷贝, 如果你只是想着传入的是 Source_Root->left, Target_Root , 那么就很难递归了
}
}
3.私有的void BinaryTree::BuildTree(const node* Source_Root, node* &Target_Root)函数
void BinaryTree::BuildTree(const node* Source_Root, node* &Target_Root) { // static 函数 参数是node* 表示树的根节点, 可以在没有对象时调用
if (Source_Root == NULL) { // 但是这里的递归 你要把参数理解成 每个节点 而不是根节点
Target_Root = NULL;
}
else {
Target_Root = new node(Source_Root->ele);
BuildTree(Source_Root->left, Target_Root->left);
BuildTree(Source_Root->right, Target_Root->right); //相当于对每个节点进行拷贝, 如果你只是想着传入的是 Source_Root->left, Target_Root , 那么就很难递归了
}
}
4.私有的void BinaryTree::BuildTree(const int* arr, int len, node* &root) 函数
void BinaryTree::BuildTree(const int* arr, int len, node* &root) { // static 函数 参数是node* 表示树的根节点, 可以在没有对象时调用
for (int i = 0; i < len; i++) { // 这里没有使用递归
int ele = arr[i];
node* tmp = root;
if (tmp == NULL) {
root = new node(ele);
}
while (tmp != NULL) {
if (ele < tmp->ele && tmp->left == NULL) {
tmp->left = new node(ele);
break;
}
else if (ele < tmp->ele && tmp->left != NULL) {
tmp = tmp->left;
}
else if (ele > tmp->ele && tmp->right == NULL) {
tmp->right = new node(ele);
break;
}
else if (ele > tmp->ele && tmp->right != NULL) {
tmp = tmp->right;
}
else {
return;
}
}
}
}
5.4.私有的void BinaryTree::BuildTree(const int* arr, int len, node* &root) 函数
void BinaryTree::preorder(const node* p) { // static 函数 参数是node* 表示树的根节点, 可以在没有对象时调用
if (p != NULL) {
cout << p->ele << " ";
preorder(p->left);
preorder(p->right);
}
} // static 函数
5.排序二叉树删除操作
void BinaryTree::Delete(int ele) {
if (root == NULL) { //如果树为空的话就直接退出函数, 要是没有这句话,后面
return; //point->ele就会报错,因为为树为空的时候,root为空
}
node* point = root; //point表示删除元素在 二叉树中的位置
node* father = NULL; father表示point的父节点
while (point->ele != ele) { //寻找删除元素在树中位置
father = point;
if (ele < point->ele) {
point = point->left;
}
else {
point = point->right;
}
if (point == NULL) {
return;
}
}
//若p没有左结点,直接用p的右结点取代它(把p的父节点原本指向p改变为p的父节点指向p的右节点).
if (point->left == NULL) { // 如果是根节点要单独考虑,因为根节点是没有父节点的,
if (point == root) {
root = root->right;
}
else {
if (father->left == point) { //判断待删除结点是其双亲结点的左节点
father->left = point->right;
}
else {
father->right = point->right;
}
}
delete point;
point = NULL;
//如果有左节点,那么找到被删节点左边最大的元素(以被删元素左节点为根的子树的最右边元素),把这个元素的值来替换被删节点的元素值,并且删除被删节点左边最大的元素。
}else {
node* r = point->left; //r表示被删节点左边最大的元素(以被删元素左节点为根的子树的最右边元素)的位置
father = point; //father表示r的父节点
while (r->right != NULL) { //找到左子树最大元素
father = r;
r = r->right;
}
if (father == point) { //如果father == point 表示while循环没有进去过,就表示被删节点的左节点就是左子树最大值,那么我们删除的这个节点在,所以我们要令父节点和最大元素的左子树连起来
father->left = r->left;
}
else {
father->right = r->left; //我们要令父节点和最大元素的右子树连起来
}
point->ele = r->ele;
delete r;
r = NULL;
}
}
如需要源码请点我
c++排序二叉树的出现的私有函数讨论,以及二叉树的删除操作详解的更多相关文章
- C++学习45 流成员函数put输出单个字符 cin输入流详解 get()函数读入一个字符
在程序中一般用cout和插入运算符“<<”实现输出,cout流在内存中有相应的缓冲区.有时用户还有特殊的输出要求,例如只输出一个字符.ostream类除了提供上面介绍过的用于格式控制的成员 ...
- javascript函数setInterval和setTimeout的使用区别详解
setTimeout和setInterval的使用 这两个方法都可以用来实现在一个固定时间段之后去执行JavaScript.不过两者各有各的应用场景. 方 法 实际上,setTimeout和setIn ...
- JQuery的ready函数与JS的onload的区别详解
JQuery的ready函数与JS的onload的区别:1.执行时间window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行.$(document).ready()是DOM结构绘制 ...
- Python open()函数文件打开、读、写操作详解
一.Python open()函数文件打开操作 打开文件会用到open函数,标准的python打开文件语法如下:open(name[,mode[,buffering]])open函数的文件名是必须的, ...
- JQuery(一)---- JQ的选择器,属性,节点,样式,函数等操作详解
JQuery的基本概念 JQuery是一个javascript库,JQuery凭借着简洁的语法和跨平台的兼容性,极大的简化了js操作DOM.处理事件.执行动画等操作.JQuery强调的理念是:'wri ...
- C++ Opencv split()通道分离函数 merge()通道合并函数 使用操作详解
一. split()通道分离函数 split()函数的C++版本有两个原型,他们分别是: C++: void split(const Mat& src, Mat*mvbegin);//& ...
- js函数在frame中的相互调用详解
原文章:http://www.jb51.net/article/47557.htm 一个HTML页面可以有一个或多个子框架,这些子框架以<iframe>来标记,用来显示一个独立的HTM ...
- mysql字符串函数:FIND_IN_SET()使用方法详解
语法: FIND_IN_SET(str,strlist) 第一个参数str是要查找的字符串. 第二个参数strlist是要搜索的逗号分隔的字符串列表. 假如字符串str 在由N 子链组成的字符串列表s ...
- js中字符串编码函数escape()、encodeURI()、encodeURIComponent()区别详解
1 escape()函数 定义和用法 escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串. 语法 escape(string) 参数 描述 string 必需.要被转义或 ...
随机推荐
- Ubuntu14.04 安装VMware tools
Ubuntu14.04 安装VMware tools 方法一: 1. 在VMware 11(个人的测试环境为vm 11版本)下安装Ubuntu镜像:ubuntu-14.04.1-desktop-amd ...
- Go Pentester - TCP Proxy
Building a TCP Proxy Using io.Reader and io.Writer Essentially all input/output(I/O). package main i ...
- Makefile中的奇葩字符
% : Makefile规则通配符,一般出现在目标或是依赖中 * : shell命令中的通配符,一般出现在命令中 $@:目标的名字 $^:所有依赖的名字 $<:第一个依赖的名字 $?:所有依赖中 ...
- 基于Python爬虫采集天气网实时信息
相信小伙伴们都知道今冬以来范围最广.持续时间最长.影响最重的一场低温雨雪冰冻天气过程正在进行中.预计,今天安徽.江苏.浙江.湖北.湖南等地有暴雪,局地大暴雪,新增积雪深度4-8厘米,局地可达10- ...
- mybatis连接池
连接池 在 Mybatis 中,数据源 dataSource 共有三类,分别是: UNPOOLED : 不使用连接池的数据源.采用传统的 javax.sql.DataSource 规范中的连接池,My ...
- web自动化 -- js操作(滑动屏幕、修改页面)
一.selenium对 js 的操作方法 1.先定义 js 操作 或者 定义 目标元素 2.执行 js 操作: driver.execute_script(js操作) 或者 ...
- Java-旋转字符串
描述 旋转字符串 给定一个字符串(以字符数组的形式给出)和一个偏移量,根据偏移量原地旋转字符串(从左向右旋转). 挑战 在数组上原地旋转,使用O(1)的额外空间 说明 原地旋转意味着你要在s本身进行修 ...
- Bug--时区问题导致IDEA连接数据库失败
打开cmd进入mysql,设置 set global time_zone='+8:00';
- mac下高效安装 homebrew 及完美避坑姿势 (亲测有效)
世上无难事,只要找到 Homebrew 的正确安装方式. Homebrew 是什么 Homebrew是 mac的包管理器,仅需执行相应的命令,就能下载安装需要的软件包,可以省掉自己去下载.解压.拖拽( ...
- Python 三引号
Python 三引号 Python 中三引号可以将复杂的字符串进行赋值.高佣联盟 www.cgewang.com Python 三引号允许一个字符串跨多行,字符串中可以包含换行符.制表符以及其他特殊字 ...