二叉搜索树的C++实现

    最近学习数据结构,其中二叉树是一个重难点,于是着手用C++把二叉搜索树的基本属性和操作实现了一遍。在coding的过程中,感觉自己对C++的一些语法细节和编程规范也有了更深的理解,下面贴出源码,代码中给出了必要的注释,方便自己整理思路,同时也给各位初学者以参考。

    我使用的参考书是 《数据结构与算法实现——C语言描述》  原书第二版   Mark Allen Weiss 著   冯舜玺 译

Node.h
#ifndef _NODE_H_
#define _NODE_H_

class Node {

friend class Tree;
friend class avlTree;

public:
	Node() {}
	Node(const int num_) : num(num_), lchild(nullptr), rchild(nullptr), parent(nullptr) {}
	Node(const Node* n) : num(n->num), lchild(nullptr), rchild(nullptr), parent(nullptr) {}

	Node& operator=(const Node& n) {
		num = n.num;
		lchild = rchild = parent = nullptr;
		return *this;
	}

	int getNum() {
		return num;
	}

private:
	Node* lchild;
	Node* rchild;
	Node* parent;
	int num;
};

#endif // #ifndef _NODE_H_

Tree.h
#include "Node.h"
#include <ostream>

class Tree {

	//以友元函数的形式重载"<<"运算符
	friend std::ostream& operator<<(std::ostream& os, const Tree& t);

public:
	Tree() : root(nullptr) {}//指针一定要初始化,避免因野指针而导致运行时出错
	Tree(const Tree& t);
	Tree(int a[], int length);

	Tree::~Tree() {
		emptySubTree(root);
	}

	//重载"="运算符
	Tree& operator=(const Tree& t) {
		//return Tree(t);//不能返回临时对象的引用!
		this->copyTree(t);
		return *this;
	}

	const Node* getRoot() const;
	void copyTree(const Tree& t);
	Node* insertNode(int num);
	bool deleteNode(int num);
	void emptySubTree(Node* NodePtr);
	void emptyTree();
	Node* minNode();
	Node* maxNode();
	void preorderTraversal() const;
	void preorderTraversal(Node* NodePtr) const;
	void inorderTraversal() const;
	void inorderTraversal(Node* NodePtr) const;
	void postorderTraversal() const;
	void postorderTraversal(Node* NodePtr) const;
	Node* findNode(const int num);
	Node* findNode(const int num, Node* NodePtr) const;
	void showTree(const Node *show_node) const;
	void showSubtree(const Node *show_node) const;
	void showTree() const;


private:
	void copyChild(Node* Nodeptr, const Node* p);
	Node* insertNode(int num, Node* &NodePtr);
	bool deleteNode(int num, Node* NodePtr);
	bool deleteNode(int num, Node* NodePtr, int);
	Node* minNode(Node* Nodeptr) const;
	Node* maxNode(Node* Nodeptr) const;
	void showSubtree(const Node *show_node, int& layer) const;
	void showNode(const Node *show_node, int& layer) const;

	Node* root;
};

SearchTree.cpp
#include <cassert>
#include <iostream>
#include <iomanip>
#include <stack>
#include "Tree.h"

using namespace std;

//通过数组构造一棵二叉搜索树
Tree::Tree(int a[], int length) {
	root = nullptr;//构造之前需将root指针置空,否则在insertNode()中无法判断是否为空树!
	for (int i = 0; i < length; ++i)
		insertNode(a[i], root);
}

//拷贝构造函数
Tree::Tree(const Tree& t) {
	root = nullptr;//拷贝构造之前需将root指针置空,否则在emptyTree()中会出错!
	copyTree(t);
}

//获取根节点
const Node* Tree::getRoot() const {
	return root;
}

//************************************************************************//
//查找子树的最小节点
Node* Tree::minNode(Node* Nodeptr) const {
	if (Nodeptr == nullptr) {
		cout << "Tree/SubTree is empty!" << endl;
		return nullptr;
	} else {
		while (Nodeptr->lchild != nullptr) {
			Nodeptr = Nodeptr->lchild;
		}
		return Nodeptr;
	}
}

//查找整棵树的最小节点
Node* Tree::minNode() {
	return minNode(root);
}

//************************************************************************//
//查找子树的最大节点
Node* Tree::maxNode(Node* Nodeptr) const {
	if (Nodeptr == nullptr) {
		cout << "Tree/SubTree is empty!" << endl;
		return nullptr;
	} else {
		while (Nodeptr->rchild != nullptr) {
			Nodeptr = Nodeptr->rchild;
		}
		return Nodeptr;
	}
}

//查找整棵树的最大节点
Node* Tree::maxNode() {
	return maxNode(root);
}

//************************************************************************//
//在子树中查找指定的值
Node* Tree::findNode(const int num, Node* NodePtr) const {
	if (NodePtr == nullptr) {
		cout << "Error: An empty tree/subtree!" << endl;
		return nullptr;
	}

	while (NodePtr->num != num) {
		if (num > NodePtr->num) {
			if (NodePtr->rchild != nullptr)
				NodePtr = NodePtr->rchild;
			else {
				cout << "ERROR: " << num << " is not found!" << endl;
				return nullptr;
			}
		} else {
			if (NodePtr->lchild != nullptr)
				NodePtr = NodePtr->lchild;
			else {
				cout << "Error: " << num << " is not found!" << endl;
				return nullptr;
			}
		}
	}

	assert(NodePtr->num == num);//必定已找到
	return NodePtr;
}

//在整棵二叉搜索树中查找指定的值
Node* Tree::findNode(const int num) {
	return findNode(num, root);
}

//************************************************************************//
//往二叉搜索树插入一个节点
Node* Tree::insertNode(int num, Node* &NodePtr) {
	if (NodePtr == nullptr)//空树
		NodePtr = new Node(num);

	else if (num > NodePtr->num) {
		if (NodePtr->rchild != nullptr)
			NodePtr->rchild = insertNode(num, NodePtr->rchild);
		else {
			NodePtr->rchild = new Node(num);
			NodePtr->rchild->parent = NodePtr;
		}
	}

	else if (num < NodePtr->num) {
		if (NodePtr->lchild != nullptr)
			NodePtr->lchild = insertNode(num, NodePtr->lchild);
		else {
			NodePtr->lchild = new Node(num);
			NodePtr->lchild->parent = NodePtr;
		}
	}

	//else {该点已经存在于树中,不做任何操作}

	return NodePtr;//返回插入操作之后指向新树根节点的指针
}

Node* Tree::insertNode(int num) {
	return insertNode(num, root);
}

//************************************************************************//
//删除节点。递归版本,利用哑元实现重载
bool Tree::deleteNode(int num, Node* NodePtr, int) {
	if (NodePtr == nullptr) {
		cout << "Error: Attempt to delete a nonexistent number node!" << endl;
		return false;
	} 

	if (num > NodePtr->num)
		deleteNode(num, NodePtr->rchild);
	else if (num < NodePtr->num)
		deleteNode(num, NodePtr->lchild);
	else {//已经找到需要删除的节点
		if (NodePtr->lchild && NodePtr->rchild) {//有左右子节点 			
			NodePtr->num = minNode(NodePtr->rchild)->num;//用右子树的最小节点值替换删除点的值
			deleteNode(NodePtr->num, NodePtr->rchild);//删除右子树的最小节点
		} else {
			if (NodePtr->rchild != nullptr) {//只有左子节点
				NodePtr->parent->lchild = NodePtr->rchild;
				NodePtr->rchild->parent = NodePtr->parent;
			}
			else if (NodePtr->lchild != nullptr) {//只有右子节点
				NodePtr->parent->lchild = NodePtr->lchild;
				NodePtr->lchild->parent = NodePtr->parent;
			} 
			else {//没有子节点,判断其自身是左叶子节点还是右叶子节点
				if (NodePtr->parent->lchild == NodePtr)
					NodePtr->parent->lchild = nullptr;//指针置空,避免出现野指针
				else
					NodePtr->parent->rchild = nullptr;
			}
			delete NodePtr;
		}
		return true;
	}	
}

//删除节点。另一递归版本
bool Tree::deleteNode(int num, Node* NodePtr) {
	NodePtr = findNode(num, NodePtr);//非递归方式查找
	if (NodePtr == nullptr) {//未找到指定节点
		cout << "Error: Attempt to delete a nonexistent number node!" << endl;
		return false;
	}

	if (NodePtr->lchild && NodePtr->rchild) {//同时有左右子节点,则采用替换删除
		NodePtr->num = minNode(NodePtr->rchild)->num;
		return deleteNode(NodePtr->num, NodePtr->rchild);
	} else {//子节点数不超过1个,可直接删除
		if (NodePtr->rchild != nullptr) {
			NodePtr->parent->lchild = NodePtr->rchild;
			NodePtr->rchild->parent = NodePtr->parent;
		} else if (NodePtr->lchild != nullptr) {
			NodePtr->parent->lchild = NodePtr->lchild;
			NodePtr->lchild->parent = NodePtr->parent;
		} else {
			if (NodePtr->parent->lchild == NodePtr)
				NodePtr->parent->lchild = nullptr;
			else
				NodePtr->parent->rchild = nullptr;
		}
		delete NodePtr;
		return true;
	}
}

bool Tree::deleteNode(int num) {
	//递归版本
	//return deleteNode(num, root, 0);

	//非递归版本
	return deleteNode(num, root);
}

//************************************************************************//
//清空子树
void Tree::emptySubTree(Node* NodePtr) {
	static int  count = 0;
	if (NodePtr != nullptr) {
		++count;	//cout << "递归:" << count << endl;
		emptySubTree(NodePtr->lchild);
		emptySubTree(NodePtr->rchild);
		--count;	//cout << "返回:" << count << endl;

		if (NodePtr != root) {//非根节点		
			if (0 == count) {//最后一次删除,需前将指向该节点的指针置空(其所有孩子节点内的指针成员已经delete掉)
				if (NodePtr->parent->lchild == NodePtr)
					NodePtr->parent->lchild = nullptr;
				else
					NodePtr->parent->rchild = nullptr;
				//cout << "置空:" << NodePtr->num << endl;
			}
			delete NodePtr; 

		} else {//根节点
			delete root;			
			root = nullptr;//删除后必须置空,否则会成为空悬指针!
			//NodePtr = nullptrptr;//此句无效,NodePtr是root的一个指针副本!
		}
	}
}

//清空整棵树
void Tree::emptyTree() {
	emptySubTree(root);
}

//************************************************************************//
//前序遍历子树 
void Tree::preorderTraversal(Node* NodePtr) const
{
	if (NodePtr != nullptr) {
		cout << NodePtr->num << " ";
		preorderTraversal(NodePtr->lchild);
		preorderTraversal(NodePtr->rchild);
	}
}

void Tree::preorderTraversal() const {
	preorderTraversal(root);
}

//中序遍历子树
void Tree::inorderTraversal(Node* NodePtr)  const
{
	if (NodePtr != nullptr) {
		inorderTraversal(NodePtr->lchild);
		cout << NodePtr->num << " ";
		inorderTraversal(NodePtr->rchild);
	}
}

void Tree::inorderTraversal() const {
	inorderTraversal(root);
}

//后序遍历子树
void Tree::postorderTraversal(Node* NodePtr)  const
{
	if (NodePtr != nullptr) {
		postorderTraversal(NodePtr->lchild);
		postorderTraversal(NodePtr->rchild);
		cout << NodePtr->num << " ";
	}
}

void Tree::postorderTraversal() const {
	postorderTraversal(root);
}

//************************************************************************//
//将二叉树以文件目录树的形式显示,不存在的子节点用'*'代替

//版本一:用堆栈保存每个节点的状态,递归打印整棵树
void Tree::showTree(const Node *show_node) const{
	static int num = -1;
	static stack<bool> flag;
	if (show_node != nullptr) {//打印非空节点,且检查并保存其子节点的状态
		++num;
		for (int i = 0; i < num; ++i)
			cout << "    ";
		cout.flags(ios::left);
		cout << setw(4) << show_node->num << endl; 

		if (show_node->rchild == nullptr && show_node->lchild == nullptr) {
			flag.push(false);//左右子节点指针都为空即叶子节点,保存两个状态(需要连续pop两个状态)
			flag.push(false);
		} else if(show_node->lchild == nullptr || show_node->rchild == nullptr )
			flag.push(true);//有且仅有一个子节点指针为空,保存其状态,下一次需要打印一个替代符

		showTree(show_node->lchild);//左节点先打印
		showTree(show_node->rchild);//右节点后打印
		--num;

	} else {//打印空节点替代符
		if (num != -1) {//非空树。如果是空树,在递归执行时第一次就进入此分支,有num == -1
			if (flag.top()) {
				for (int i = 0; i <= num; i++)
					cout << "    ";
				cout << setw(4) << '*' << endl;
			}
		flag.pop();//弹出节点状态
		}
	}
}

//版本二:用“前序遍历”思想直接递归打印指定的子树
void Tree::showSubtree(const Node *show_node, int& layer) const {
	if (!layer) {//根节点
		if (show_node != nullptr)//非空树则打印根节点
			showNode(show_node, layer);
		else
			return;
	}

	if (show_node != nullptr) {//非空节点
		if (show_node->lchild || show_node->rchild) {//非叶子节点,则递归打印子节点
			++layer;
			showNode(show_node->lchild, layer);
			showSubtree(show_node->lchild, layer);
			showNode(show_node->rchild, layer);
			showSubtree(show_node->rchild, layer);
			--layer;
		}
	}
}

//包装showSubtree()方法
void Tree::showSubtree(const Node *show_node) const {
	int layer = 0;
	showSubtree(show_node, layer);//必须给layer传0,显示根节点时不打印空格
}

//打印显示单个节点值或替代符,layer代表节点的深度
void Tree::showNode(const Node *show_node, int& layer) const {
	for (int i = 0; i < layer; ++i)
		cout << "    ";
	cout.flags(ios::left);	
	if (show_node != nullptr)
		cout << setw(4) << show_node->num << endl;
	else
		cout << setw(4) << '*' << endl;
}

//打印显示整棵二叉树
void Tree::showTree() const {
	//版本一
	//showTree(root);

	//版本二
	showSubtree(root);
}

//************************************************************************//
//拷贝一棵树
void Tree::copyTree(const Tree& t) {
	emptyTree();//清空自身
	if (t.root != nullptr) {
		root = new Node(t.root);//拷贝根节点
		copyChild(root, t.root);//递归拷贝每个子节点
	}
}

//拷贝当前节点的子节点
void Tree::copyChild(Node* Nodeptr, const Node* p) {
	if (p->lchild != nullptr) {
		Nodeptr->lchild = new Node(p->lchild);
		Nodeptr->lchild->parent = Nodeptr;
		copyChild(Nodeptr->lchild, p->lchild);
	}

	if (p->rchild != nullptr) {
		Nodeptr->rchild = new Node(p->rchild);
		Nodeptr->rchild->parent = Nodeptr;
		copyChild(Nodeptr->rchild, p->rchild);
	}
}

//************************************************************************//
//重载"<<"运算符
ostream& operator<<(ostream& os, const Tree& t) {
	t.inorderTraversal();//默认输出中序遍历结果,即升序显示
	return os;//保证"<<"运算符可以连续输出
}

TestTree.cpp
#include <iostream>
#include "Tree.h"

using namespace std;

int main() {

	int a[10] = { 3, 5, -5, 11, 2, 4, 5, 63, -15, 0};//有重复值5

	Tree tree1(a, sizeof(a)/sizeof(int));
	Tree tree2(tree1);
	//Tree tree3 = tree2;//初始化对象时编译器会优化,直接调用了拷贝构造函数
	Tree tree3;
	tree3 = tree2;

	cout << "tree1: " << tree1 << endl << "tree2: " << tree2 << endl << "tree3: " << tree3 << endl;

	tree1.insertNode(1);
	cout << "tree1.insertNode(1): " << tree1 << endl;

	tree1.insertNode(-5);//插入已经存在的点
	cout << "tree1.insertNode(5): " << tree1 << endl;

	tree1.deleteNode(3);//删除根节点
	cout << "tree1.deleteNode(3): " << tree1 << endl;

	tree1.deleteNode(8);//删除不存在的节点
	cout << "tree1.deleteNode(8): " << tree1 <<endl;

	cout << "tree1目录树:" << endl;
	tree1.showTree();

	return 0;
}

测试输出结果为:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值