一天一个算法,边回想算法细节,边捡回C++,试验性程序,留作记念。
设计思路
设计一个类,根结点只可读取,具备构造二叉树、插入结点、删除结点、查找、 查找最大值、查找最小值、查找指定结点的前驱和后继等功能接口。
二叉排序树概念
它或者是一棵空树;或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树。
二叉排序树的各种操作
插入新节点
这是一个递归操作,递归设计时要找到最源头,才能得到最简设计。一种设计是判断叶子节点,把新节点作为叶子节点的孩子插入;一种是永远当作根进行插入,插入节点永远是当前子树的根!看代码:
//root为二级指针的原因是,如果树为空,需要将根修改反馈回来
bool BinaryTree::InsertNode(pNode * cuRoot, int data, pNode self)
{ //递归设计时找到最源头,才能得到最简设计
if (*cuRoot == nullptr){
pNode node = new Node;
if (node == nullptr)
return false;
node->data = data;
node->lChild = node->rChild = node->parent = nullptr;
(*cuRoot) = node;
node->parent = self;
return true;
}
if (data > (*cuRoot)->data)
InsertNode(&(*cuRoot)->rChild, data, *cuRoot);
else
InsertNode(&(*cuRoot)->lChild, data, *cuRoot);
return true;
}
构造函数
一共两个重载函数:一个无参,一个接受数组利用插入函数直接构造二叉排序树。
BinaryTree::BinaryTree(int * datum, int len)
{
root = nullptr;
for (int i = 0; i < len; i++)
InsertNode(&root, datum[i], root);
}
BinaryTree::BinaryTree()
{
root = nullptr;
}
查找函数
这也是一个递归操作,为了对外隐藏root(根节点),因此编写了一个私有函数,进行真正的查找操作。
//真正的查找函数
BinaryTree::pNode BinaryTree::_searchKey(pNode root, int key){
if (root == nullptr)
return nullptr;
if (root->data == key) //找到了
return root;
else if (root->data > key)//值偏小,到左子树找
return _searchKey(root->lChild, key);
else //值偏大,到右子树找
return _searchKey(root->rChild, key);
}
//对外接口
BinaryTree::pNode BinaryTree::SearchKey(int key){
return _searchKey(root, key);
}
找前驱节点
要么为左子树中最大者,要么一直追溯其父节点链,第一个是其父节点的右孩子的父节点,即为所求。
BinaryTree::pNode BinaryTree::SearchPredecessor(pNode node){
if (node == nullptr)
return nullptr;
else if (node->lChild != nullptr)
return SearchMaxNode(node->lChild);
else
{
if (node->parent == nullptr)
return nullptr;
while (node)
{
if (node->parent->rChild == node)
break;
node = node->parent;
}
return node->parent;
}
}
找后继节点
与找前驱节点基本相似。
要么为右子树中最小者,要么一直追溯其父节点链,第一个是其父节点的左孩子的父节点,即为所求。
BinaryTree::pNode BinaryTree::SearchSuccessor(pNode node){
if (node == nullptr)
return nullptr;
else if (node->rChild != nullptr)
return SearchMinNode(node->rChild);
else
{
if (node->parent == nullptr)
return nullptr;
while (node)
{
if (node->parent->lChild == node)
break;
node = node->parent;
}
return node->parent;
}
}
找最小值
BinaryTree::pNode BinaryTree::SearchMinNode(pNode curNode){
if (curNode == nullptr)
return nullptr;
//一直找到左子树为空的节点,即为最小值
while (curNode->lChild != nullptr)
curNode = curNode->lChild;
return curNode;
}
找最大值
BinaryTree::pNode BinaryTree::SearchMaxNode(pNode curNode){
if (curNode == nullptr)
return nullptr;
//一直找到右子树为空的节点,即为最大值
while (curNode->rChild != nullptr)
curNode = curNode->rChild;
return curNode;
}
中序遍历
void BinaryTree::_visitMiddle(pNode root){
if (root != nullptr){
_visitMiddle(root->lChild);
printf("%d;", root->data);
_visitMiddle(root->rChild);
}
}
void BinaryTree::VisitMiddle(){
_visitMiddle(root);
}
删除节点
这个是最麻烦的操作,分四种情况分别处理,最麻烦的是被删节点左右子树都存在的情况,这时将被删节点内容换成其后继内容,删除其后继(递归)。
bool BinaryTree::DeleteNode(int key){
//return _deleteNode(root, key);
pNode node = SearchKey(key);
if (!node)
return false;
//被删节点为叶子结点
if (node->lChild == nullptr && node->rChild == nullptr){
if (node->parent == nullptr){
root = nullptr;
}
else
{
if (node->parent->lChild == node)
node->parent->lChild = nullptr;
else
node->parent->rChild = nullptr;
}
delete node;
}
//被删节点只有左子树
else if (node->lChild != nullptr && node->rChild == nullptr){
//将左孩子的父亲指向被删节点的父亲
node->lChild->parent = node->parent;
//被删节点为根,修改根节点
if (node->parent == nullptr)
root = node->lChild;
else if(node->parent->lChild == node)
node->parent->lChild = node->lChild;
else
node->parent->rChild = node->lChild;
delete node;
}
//被删节点只有右子树
else if (node->lChild == nullptr && node->rChild != nullptr){
//将右孩子的父亲指向被删节点的父亲
node->rChild->parent = node->parent;
//被删节点为根,修改根节点
if (node->parent == nullptr)
root = node->rChild;
else if (node->parent->lChild == node)
node->parent->lChild = node->rChild;
else
node->parent->rChild = node->rChild;
delete node;
}
//被删节点左、右子树都有
else { //用后继节点取代删除节点,并删除后继
pNode successor = SearchSuccessor(node);
int temp = successor->data;
DeleteNode(temp);
node->data = temp;
}
}
柝构函数
函数超出作用域范围时,清理占用内存。
BinaryTree::~BinaryTree()
{
_delAllNode(root);
}
void BinaryTree::_delAllNode(pNode root){
if (root != nullptr && root!=NULL){
_delAllNode(root->lChild);
_delAllNode(root->rChild);
DeleteNode(root->data);
}
}
类的定义(头文件)
#pragma once
#include<stdio.h>
#include<stdlib.h>
class BinaryTree
{
private:
typedef struct Node{
struct Node * parent;
struct Node * lChild;
struct Node * rChild;
int data;
}*pNode;
pNode root;
void _visitMiddle(pNode root);
pNode _searchKey(pNode root, int key);
void _delAllNode(pNode root);
public:
BinaryTree();
BinaryTree(int * datum, int len);
pNode SearchMaxNode(pNode node);
pNode SearchMinNode(pNode node);
pNode GetRoot();
pNode SearchKey(int key);
bool DeleteNode(int key);
pNode SearchPredecessor(pNode node);
pNode SearchSuccessor(pNode node);
void VisitMiddle();
bool InsertNode(pNode * cuRoot, int data, pNode self);
~BinaryTree();
};
调用示例
#include <conio.h>
#include "BinaryTree.h"
int main()
{
int arrs[] = { 23, 65, 12, 3, 8, 76, 90, 21, 75, 34,345, 61 };
int len = sizeof(arrs) / sizeof(arrs[0]);
BinaryTree bTree(arrs,len);
bTree.DeleteNode(90);
bTree.VisitMiddle();
getch();
return 0;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。