算法与数据结构基础11:C++实现——二拆搜索树节点删除

基于我的另一篇文章《算法与数据结构基础4:C++二叉树实现及遍历方法大全》 ,二叉树的结构用的这篇文章里的。

二查找叉树的删除可以细分为三种情况:

1 被删除的是叶子节点,直接删除;

2 被删除只有一个子节点,指针下移;

3 有两个子节点,为了不破坏树的结构,需要找出一个节点来替换当前节点。

根据二叉树的特点,当前节点大于所有左子树,小于所有右子树,

可以用左子树中最大的节点,或者右子树最小的节点来替换当前节点,然后删除替换节点。

// BSTree.h

#include <cstdio>
#include <iostream>
#include <stack>
#include <queue>

using namespace std;

// binary search tree,中文翻译为二叉搜索树、二叉查找树或者二叉排序树。简称为BST
class BSTree
{
	struct Node{
		Node(int x = 0):data(x), lchild(NULL), rchild(NULL){}
		struct Node* lchild;
		struct Node* rchild;
		int data;
	};

public:
	// **************************************************************************
	// 类的四大函数:构造函数、拷贝构造函数、重载赋值运算符、析构函数
	// **************************************************************************
	BSTree();
	~BSTree();

	// **************************************************************************
	// 增删改查
	// **************************************************************************
	void Insert(int x);
	void Remove(int x);

	// 返回二叉树的个数
	unsigned short Size();
	unsigned short Deep();
	unsigned short Leaf();

	bool IsEmpty();

	// 遍历
	void PreorderTraversal();	// 先序遍历
	void InorderTraversal();	// 中序遍历
	void PostorderTraversal();	// 后序遍历
	void DepthFirstSearch();	// 深度优先遍历
	void BreadthFirstSearch();	// 广度优先遍历

private:
	void Remove(int x, Node** pNode);

	// 递归计算二叉树个数
	unsigned short CountSize(Node* n);
	unsigned short CountDeep(Node* n);
	unsigned short CountLeaf(Node* n);

	// 递归遍历
	void PreorderTraversal(Node* n);
	void InorderTraversal(Node* n);
	void PostorderTraversal(Node* n);
	void DepthFirstSearch(Node* n);
	void BreadthFirstSearch(Node* n);

	void Free(Node* node);
private:
	Node* m_root;
};

// **************************************************************************
// 私有方法
// **************************************************************************
/*
//1 请问下面这份代码有什么问题?
void BSTree::Remove(int x, Node* node)
{
	if (!node) {
		return;
	}
	if (x < node->data) {
		Remove(x, node->lchild);
	}
	else if (x > node->data){
		Remove(x, node->rchild);
	}
	else if (node->lchild && node->rchild) {
		Node* min = node->rchild;
		while(min->lchild){
			min = min->lchild;
		}
		node->data = min->data;
		Remove(node->data, node->rchild);
	}
	else{
		Node* tmp = node;
		if(node->lchild){
			node = node->lchild;
		}
		else if (node->rchild){
			node = node->rchild;
		}
		else{
			node = NULL;
		}
		delete tmp;
		tmp = NULL;
	}
}
node是一个局部变量,对node的操作除delete之外都不会生效

// 2 再问,下面的代码有什么问题?
void BSTree::Remove(int x, Node** pNode)
{
	if (!pNode || !(*pNode)) {
		return;
	}
	Node* node = *pNode;
	if (x < node->data) {
		Remove(x, node->lchild);
	}
	else if (x > node->data){
		Remove(x, node->rchild);
	}
	else if (node->lchild && node->rchild) {
		Node* min = node->rchild;
		while(min->lchild){
			min = min->lchild;
		}
		node->data = min->data;
		Remove(node->data, node->rchild);
	}
	else{
		Node* tmp = node;
		if(node->lchild){
			node = node->lchild;
		}
		else if (node->rchild){
			node = node->rchild;
		}
		else{
			node = NULL;
		}
		delete tmp;
		tmp = NULL;
	}
}
同样的问题,虽然这里传递的参数是指针,但是Node* node = *pNode;发生了拷贝。

*/
void BSTree::Remove(int x, Node** pNode)
{
	if (!pNode || !(*pNode)) {
		return;
	}

	if (x < (*pNode)->data) {
		Remove(x, &((*pNode)->lchild));
	}
	else if (x > (*pNode)->data){
		Remove(x, &((*pNode)->rchild));
	}
	else if ((*pNode)->lchild && (*pNode)->rchild) {
		Node* min = (*pNode)->rchild;
		while(min->lchild){
			min = min->lchild;
		}
		(*pNode)->data = min->data;
		Remove((*pNode)->data, &((*pNode)->rchild));
	}
	else{
		Node* tmp = *pNode;
		if((*pNode)->lchild){
			(*pNode) = (*pNode)->lchild;
		}
		else if ((*pNode)->rchild){
			*pNode = (*pNode)->rchild;
		}
		else{
			*pNode = NULL;
		}
		delete tmp;
		tmp = NULL;
	}
}

unsigned short BSTree::CountSize(Node* n)
{
	if(!n){
		return 0;
	}

	return CountSize(n->lchild) + CountSize(n->rchild) + 1;
}

unsigned short BSTree::CountDeep(Node* n)
{
	if (!n) {
		return 0;
	}
	int ldeep = CountDeep(n->lchild);
	int rdeep = CountDeep(n->rchild);
	return ( ldeep > rdeep ) ? (ldeep + 1) : (rdeep + 1);
}

unsigned short BSTree::CountLeaf(Node* n)
{
	if (!n){
		return 0;
	}
	if (!n->lchild&& !n->rchild){
		return 1;
	}
	return CountLeaf(n->lchild) + CountLeaf(n->rchild);
}

void  BSTree::PreorderTraversal(Node* n)
{
	if (n) {
		cout << n->data << ",";
		PreorderTraversal(n->lchild);
		PreorderTraversal(n->rchild);
	}
}

void  BSTree::InorderTraversal(Node* n)
{
	if (n) {
		InorderTraversal(n->lchild);
		cout << n->data << ",";
		InorderTraversal(n->rchild);
	}
}

void  BSTree::PostorderTraversal(Node* n)
{
	if (n) {
		PostorderTraversal(n->lchild);
		PostorderTraversal(n->rchild);
		cout << n->data << ",";
	}
}

void BSTree::DepthFirstSearch(Node* root)
{
	stack<Node *> nodeStack;
	nodeStack.push(root);
	Node* node = NULL;
	while(!nodeStack.empty()){
		node = nodeStack.top();
		cout << node->data << ",";
		nodeStack.pop();
		if (node->rchild) {
			nodeStack.push(node->rchild);
		}
		if (node->lchild) {
			nodeStack.push(node->lchild);
		}
	}
}

void BSTree::BreadthFirstSearch(Node* root)
{
	queue<Node *> nodeQueue;
	nodeQueue.push(root);
	Node* node = NULL;
	while(!nodeQueue.empty()){
		node = nodeQueue.front();
		nodeQueue.pop();
		cout << node->data << ",";
		if (node->lchild) {
			nodeQueue.push(node->lchild);
		}
		if (node->rchild) {
			nodeQueue.push(node->rchild);
		}
	}
}

void BSTree::Free(Node* n)
{
	if (n) {
		Free(n->lchild);
		Free(n->rchild);
		delete n;
		n = NULL;
	}
}

// **************************************************************************
// 类的四大函数:构造函数、拷贝构造函数、重载赋值运算符、析构函数
// **************************************************************************
BSTree::BSTree()
{
	m_root = NULL;
}

BSTree::~BSTree()
{
	Free(m_root);
}

// **************************************************************************
// 增删改查
// **************************************************************************
void BSTree::Insert(int x)
{
	Node* tmp = new Node(x);
	if (!m_root){
		m_root = tmp;
	}
	else{
		Node* pre = m_root;
		Node* cur = m_root;
		while (cur){
			pre = cur;
			cur = (x < cur->data) ? (cur->lchild) : (cur->rchild);
		}
		(x < pre->data) ? (pre->lchild = tmp) : (pre->rchild = tmp);
	}
}

void BSTree::Remove(int x)
{
	if (!m_root){
		return;
	}
	Remove(x, &m_root);
}

unsigned short BSTree::Size()
{
	return CountSize(m_root);
}

unsigned short BSTree::Deep()
{
	return CountDeep(m_root);
}

unsigned short BSTree::Leaf()
{
	return CountLeaf(m_root);
}

bool BSTree::IsEmpty()
{
	return m_root == NULL;
}

void BSTree::PreorderTraversal()
{
	PreorderTraversal(m_root);
	cout << endl;
}

void BSTree::InorderTraversal()
{
	InorderTraversal(m_root);
	cout << endl;
}

void BSTree::PostorderTraversal()
{
	PostorderTraversal(m_root);
	cout << endl;
}

void BSTree::DepthFirstSearch()
{
	DepthFirstSearch(m_root);
	cout << endl;
}

void BSTree::BreadthFirstSearch()
{
	BreadthFirstSearch(m_root);
	cout << endl;
}

// main.cpp

// test for BSTree
#include "BSTree.h"
#include <cstdlib>
#include <iostream>

using namespace std;

int main()
{
	BSTree tree;
	int arr[6] = {5, 4, 8, 1, 7, 10};
	for (int i = 0; i < 6; ++i){
		tree.Insert(arr[i]);
	}

	tree.PreorderTraversal();
	tree.InorderTraversal();
	tree.PostorderTraversal();
	tree.DepthFirstSearch();
	tree.BreadthFirstSearch();

	tree.Remove(4);
	tree.PreorderTraversal();

	tree.Remove(1);
	tree.PreorderTraversal();

	tree.Remove(10);
	tree.PreorderTraversal();

	cout << "size:" << tree.Size() << endl;
	cout << "deep:" << tree.Deep() << endl;
	cout << "leaf:" << tree.Leaf() << endl;

	system("pause");
	return 0;
}

// 树的结构

// 运行结果截图

时间: 2024-08-26 07:22:27

算法与数据结构基础11:C++实现——二拆搜索树节点删除的相关文章

算法与数据结构基础10:C++实现——拓扑排序

一 定义 拓扑排序是对有向无环图(Directed Acyclic Graph简称DAG)顶点的一种排序, 它使得如果存在一条从顶点A到顶点B的路径,那么在排序中B出现在A的后面. 二 先决条件 能够进行拓扑排序图有两个先决条件:有向.无环,即有向无环图. 三 偏序全序 连通图:任意两点之间都存在至少一条边 偏序:非连通图(有向无环图满足偏序关系) 全序:单连通图 四 结果唯一性 对于仅满足偏序关系的有向无环图中,因为有两个点之间的关系是不确定的,所以导致排序的结果是不唯一的. 满足全序关系的有

算法与数据结构基础 - 广度优先搜索(BFS)

BFS基础 广度优先搜索(Breadth First Search)用于按离始节点距离.由近到远渐次访问图的节点,可视化BFS 通常使用队列(queue)结构模拟BFS过程,关于queue见:算法与数据结构基础 - 队列(Queue) 最直观的BFS应用是图和树的遍历,其中图常用邻接表或矩阵表示,例如 LeetCode题目 690. Employee Importance: // LeetCode 690. Employee Importance/* class Employee { publi

算法与数据结构基础1:动态数组

恶补算法与数据结构,从很基础的开始,先看动态数组的实现. // array.h #include <iostream> #include <cstring> #include <cstdlib> using namespace std; class Array { public: // ************************************************************************** // 类的四大函数:构造函数.拷贝构

算法与数据结构基础4:C++二叉树实现及遍历方法大全

binary search tree,中文翻译为二叉搜索树.二叉查找树或者二叉排序树.简称为BST. 本文集齐了二叉树的五大遍历算法:先序遍历.中序遍历.后序遍历.深度优先遍历和广度优先遍历(同层遍历也就是深度优先遍历). // BSTree.h #include <cstdio> #include <iostream> #include <stack> #include <queue> using namespace std; // binary sear

【算法导论】动态规划之“最优二叉搜索树”

之前两篇分别讲了动态规划的"钢管切割"和"矩阵链乘法",感觉到了这一篇,也可以算是收官之作了.其实根据前两篇,到这里,也可以进行一些总结的,我们可以找到一些规律性的东西. 所谓动态规划,其实就是解决递归调用中,可能出现重复计算子问题,从而导致耗费大量时间,去做重复劳动的问题.解决思路就是,将重复做过的子问题的结果,先存起来,等之后再需要用到的时候,直接拿过来用,而不需要再去计算. 但是这里还需要注意一些地方: ①要解决的问题,比如"钢管切割"中的

数据结构(六)查找---二叉搜索树(排序树)

前提 前面的查找我们都是静态查找,因为数据集是有序存放,查找的方法有多种,可以使用折半,插值,斐波那契等,但是因为有序,在插入和删除操作上的效率并不高. 这时我们就需要一种动态查找方法,既可以高效实现查找,又可以使得插入和删除效率不错,这时我们可以考虑二叉排序树 二叉排序树 一:定义 又称为二叉搜索树(查找树),是一棵树,可以为空,但是需要满足以下性质: 1.非空左子树的所有键值小于其根节点的键值 2.非空右子树的所有键值大于其根节点的键值 3.左右子树都是二叉搜索树 二:操作 查找 /* Bi

算法和数据结构基础题集(持续更新中)

 注意一题多解,举一反三,从普通算法到最优算法 1.判断一个字符串中的字符是否唯一(即没有重复),不能使用额外的数据结构(使用基本的数据结构) 2.反转一个字符串 3.去掉字符串中的重复字符,不能使用额外的缓存空间 4.判断两个字符串是否是变位词(两个单词字符相同,但是位置不同的单词) 5.写一函数,把字符串的空格替换为%20 6.判断字符串是否是另一个字符串的字串 7.从一个未排序的链表去除重复的项,不允许使用临时的缓存 8.从一个单链表中返回倒数第k个元素 9.删除链表中的给定节点 10

算法与数据结构基础9:C++实现有向图邻接矩阵存储

邻接矩阵的存储比邻接表实现起来更加方便,也更加容易理解. 邻接矩阵就是用一个二维数组matrix来存储每两个点的关系.如果两个点m,n之间有边,将数组matrix[]m[m]设为1,否则设为0. 如果有权,则将matrix[m]n[]设为权值,定义一个很大或者很小的数(只要不跟权值冲突即可),表示不相连. 空间复杂度为O(V^2),适合比较稠密的图. 邻接表O(V+E),适合比较稀疏的图. //GraphMatrix.h #include <iostream> #include <cst

算法与数据结构基础7:C++双链表的简单实现

双链表在单链表的基础上加了一个指向前一个节点的指针. // DList.h #include <cstdio> #include <cassert> #include <iostream> using namespace std; class DList { public: // ************************************************************************** // 类的四大函数:构造函数.拷贝构造函数