函数递归调用图
二叉树
// 二叉树.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <stdio.h>
struct Node {
int nData; // 节点的数据域
Node* pLeft; // 左子树指针
Node* pRight; // 右子树指针
Node() :pLeft(), pRight() {}
Node(int nData)
:nData(nData),pLeft(), pRight()
{}
};
// 二叉查找树
class BSTree {
int m_nCount = 0; // 树中节点个数
Node* m_pRoot = 0;// 根节点指针:记录树中的根节点地址.
protected:
// 参数1是指针的引用, 为的是能够在
// 函数内部修改函数外部的实参(可以参考交换两个变量的函数)
/*!
* 函数名 : insert
* 功 能 : 将数据nData插入到pTree作为根节点的树居中
* 参 数 : Node * & pTree 树的根节点.
* 参 数 : int nData 插入的数据
* 返回值 : void
*/
void insert( Node*& pTree, int nData) {
// 1. 判断树的根节点是否为NULL,如果为NULL
// 直接插入到根节点
if (pTree == nullptr) {
pTree = new Node(nData);
// 递增节点个数
++m_nCount;
return;
}
// 2. 如果不为空,则判断插入的数据和根节点
// 所保存的数据的大小关系
if (nData < pTree->nData) {
// 3. 如果插入数据小于根节点数据,那么就将
// 根节点的左子树作为新的根节点,让后将
// 数据插入到左子树中.
insert(pTree->pLeft, nData);
}
else {
// 否则就插入到右子树中.
insert(pTree->pRight, nData);
}
}
Node*& find(Node*& pTree, int nData) {
if (pTree == nullptr) {
return pTree;
}
// 1. 判断当前节点保存的数据是否
// 就是要查找的数据
if (pTree->nData == nData) {
// 如果是, 就返回节点本身
return pTree;
}
// 如果不是, 则判断这个数据是在节点的左子树中
// 还是在右子树中.
// 因为二叉树是左小右大的.
// 因此, 比较要删除的数据和当前节点的大小关系
// 就能知道是在左子树还是在右子树中
else if (nData < pTree->nData) {
return find(pTree->pLeft,nData);
}
else {
return find(pTree->pRight,nData);
}
}
void remove(Node*& pTree, int nData) {
if (pTree == nullptr) {
return;
}
printf("-------- 删除:%d----- \n", nData);
printTree();
// 1. 在树中查找到要删除的节点.
Node*& pFindNode = find(pTree, nData);
// 是否能够找到节点.
if (pFindNode == nullptr) {
return;
}
// 2. 找到节点的就是被删除的节点
// 删除时要判断节点是否是一个叶子节点
// 如果是叶子节点可以直接删除
if (pFindNode->pLeft == nullptr && pFindNode->pRight == nullptr) {
// 直接删除
delete pFindNode;
// 将指针设置为空,由于pFindNode是一个指针
// 的引用, 因此它修改的是哪里????(实际上修改的是
// 父节点的右子树指针或左子树指针)
pFindNode = nullptr;
// 递减节点个数
--m_nCount;
return;
}
// 3. 如果不是叶子节点. 就需要在被删除节点的
// 子树中找到一个叶子节点, 然后两者的值
// 互换, 再删除掉叶子节点
// 3.1 再找叶子节点的时候, 需要考虑子树高度差
// 因此会在树高比较高的子树中找叶子节点.
int nLeftHeight = getHeight(pFindNode->pLeft);
int nRightHeight = getHeight(pFindNode->pRight);
// 3.2 树中左小右大的关系, 因此, 需要左子树中
// 找最大值, 在右子树中找最小值.
if (nLeftHeight >= nRightHeight) {
// 左子树比较高,需要找最大值
Node*& pNode = getMax(pFindNode->pLeft);
// 将当前被找到的节点和叶子节点的数据域
// 进行调换
int t = pFindNode->nData;
pFindNode->nData = pNode->nData;
pNode->nData = t;
// 删除叶子节点
// 递归删除.
remove(pFindNode->pLeft, pNode->nData);
}
else {
// 右子树比较高,需要找最小值
Node*& pNode = getMin(pFindNode->pRight);
int t = pFindNode->nData;
pFindNode->nData = pNode->nData;
pNode->nData = t;
// 删除叶子节点
// 递归删除.
remove(pFindNode->pRight, pNode->nData);
}
}
/*!
* 函数名 : getHeight
* 功 能 : 求一个树的高度
* 参 数 : Node * pTree
* 返回值 : int
*/
int getHeight(Node* pTree) {
if (pTree == nullptr) {
return 0;
}
// 求出左子树的高度
int nLeftHeight =
getHeight(pTree->pLeft);
// 求出右子树的高度
int nRightHeight =
getHeight(pTree->pRight);
// 取左右子树高度的最大值作为子树的高度
int nHeight = nLeftHeight > nRightHeight ? nLeftHeight : nRightHeight;
// 本节点的高度 = 自身高度 + 子树的高度
return 1 + nHeight;
}
Node*& getMin(Node*& pTree) {
if (pTree == nullptr) {
return pTree;
}
// 二叉树是左小右大的.
// 一个树的最小值就在树的最左边
if (pTree->pLeft == nullptr) {
// 如果本节点的左子节点已经为空了
// 说明了本节点就是树中最左边的节点
// 就返回节点自身.
return pTree;
}
return getMin(pTree->pLeft);
}
Node*& getMax(Node*& pTree) {
if (pTree == nullptr) {
return pTree;
}
// 二叉树是左小右大的.
// 一个树的最大值就在树的最右边
if (pTree->pRight == nullptr) {
// 如果本节点的右子节点已经为空了
// 说明了本节点就是树中最右边的节点
// 就返回节点自身.
return pTree;
}
return getMax(pTree->pRight);
}
// 清空整颗树(后序遍历
void clear(Node*& pTree) {
clear(pTree->pLeft);
clear(pTree->pRight);
delete pTree;
}
// 前序方式遍历树
void printTreeByPreOrder(Node*& pTree) {
if (pTree == nullptr) {
return;
}
printf("%d,", pTree->nData);
printTreeByPreOrder(pTree->pLeft);
printTreeByPreOrder(pTree->pRight);
}
// 中序方式遍历树
void printTreeByInOrder(Node*& pTree) {
if (pTree == nullptr) {
return;
}
printTreeByInOrder(pTree->pLeft);
printf("%d,", pTree->nData);
printTreeByInOrder(pTree->pRight);
}
// 后序方式遍历树
void printTreeByPostOrder(Node*& pTree) {
if (pTree == nullptr) {
return;
}
printTreeByPostOrder(pTree->pLeft);
printTreeByPostOrder(pTree->pRight);
printf("%d,", pTree->nData);
}
void printTree(Node*& pTree, int nWidth, char ch) {
if (pTree == nullptr) {
return;
}
printTree(pTree->pLeft, nWidth + 2, '/');
printf("%*c%d\n", nWidth, ch , pTree->nData);
printTree(pTree->pRight, nWidth + 2, '\\');
}
void sort(Node*& pTree) {
// 1. 判断树的形状:
int nLeftHeight = getHeight(pTree->pLeft);
int nRightHeight = getHeight(pTree->pRight);
if (nLeftHeight - nRightHeight > 1) {
// 1.1 左斜
nLeftHeight = getHeight(pTree->pLeft->pLeft);
nRightHeight = getHeight(pTree->pLeft->pRight);
if (nLeftHeight > nRightHeight) {
// 1.1.1 左单斜
}
else {
// 1.1.2 左歪斜
}
}
else if (nLeftHeight - nRightHeight < -1) {
// 1.2 右斜
nLeftHeight = getHeight(pTree->pRight->pLeft);
nRightHeight = getHeight(pTree->pRight->pRight);
if (nRightHeight > nLeftHeight) {
// 1.2.1 右单斜
}
else {
// 1.2.2 右歪斜
}
}
}
public:
void insert(int nData) {
insert(m_pRoot, nData);
}
void remove(int nData) {
remove(m_pRoot, nData);
}
void printTree() {
printTree(m_pRoot, 2, '*');
printf("\n");
}
};
struct MyStruct {
int nNum = 0;
const char* pStr;
};
const char*& fun(const char*& p) {
return p;
}
int main(){
MyStruct stc = {0, "hello" };
const char*& p = fun(stc.pStr);
p = "呵呵";
BSTree tree;
tree.insert(10);
tree.insert(5);
tree.insert(20);
tree.insert(7);
tree.insert(6);
tree.printTree();
tree.remove(10);
tree.printTree();
}