铺垫知识:
0.0 二叉树的遍历
遍历分: 前序遍历、中序遍历、后续遍历
- 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
- 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
- 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。
整体代码:
typedef char BTDataType;
typedef struct BinaryTreeNode
{
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
BTDataType data;
}BTNode;
BTNode* BuyNode(BTDataType x)
{
BTNode* node = (BTNode*)malloc(sizeof(BTNode)); //创建了一个指针变量node
if (node == NULL)
{
printf("malloc fail\n");
exit(-1);
}
node->data = x;
node->left = node->right = NULL;
return node;
}
BTNode* CreatBinaryTree()
{
BTNode* nodeA = BuyNode('A');
BTNode* nodeB = BuyNode('B');
BTNode* nodeC = BuyNode('C');
BTNode* nodeD = BuyNode('D');
BTNode* nodeE = BuyNode('E');
BTNode* nodeF = BuyNode('F');
nodeA->left = nodeB;
nodeA->right = nodeC;
nodeB->left = nodeD;
nodeC->left = nodeE;
nodeC->right = nodeF;
return nodeA;
}
// 二叉树前序遍历
void PreOrder(BTNode* root)
{
if (root == NULL){
printf("NULL ");
return;
}
printf("%c ", root->data); //根
PreOrder(root->left); //左子树
PreOrder(root->right); //右子树
}
// 二叉树中序遍历
void InOrder(BTNode* root)
{
if (root == NULL){
printf("NULL ");
return;
}
InOrder(root->left);
printf("%C ", root->data);
InOrder(root->right);
}
int main()
{
BTNode* root = CreatBinaryTree();
PreOrder(root);
printf("\n");
InOrder(root);
printf("\n");
}
0.1 前序遍历
代码部分
// 二叉树前序遍历
void PreOrder(BTNode* root)
{
if (root == NULL){
printf("NULL ");
return; //return是回到调用我的地方
}
printf("%c ", root->data); //根
PreOrder(root->left); //左子树
PreOrder(root->right); //右子树
}
流程图:
0.2 中序
代码部分:
void InOrder(BTNode* root)
{
if (root == NULL){
printf("NULL ");
return;
}
InOrder(root->left); //左子树
printf("%C ", root->data); //根
InOrder(root->right); //右子树
}
流程图:
0.3 后序
作用:搜索查找一个数,最多查找高度次O(N)
概念:(二叉排序树)或者是一棵空树
int a[] ={5,3,4,1,7,8,2,6,0,9}
性质如下:
- 若左子树不为空,则左子树的所有节点 < 根节点的值
- 若右子树不为空,则右子树所有节点 > 根节点的值
- 左右子树也分别为二叉搜索树
整体代码:
BinarySerchTree.h
#pragma once
template<class K> //创建函数模板。k可以是任何类型
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
, _right(nullptr)
, _key(key)
{}
};
template<class K>
struct BSTree
{
typedef BSTreeNode<K> Node; //将BSTreeNode<K>重命名为Node
public:
BSTree()
:_root(nullptr)
{}
bool Insert(const K& key)
{
if (_root == nullptr) //空树
{
_root = new Node(key); //new int(10)动态申请一个int类型的空间并初始化为10
return true; //在申请自定义类型的空间时,new会调用构造函数
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key < key) //比你大,往右走
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else //相等则说明,值已经存在
{
return false;
}
}
cur = new Node(key);
//链接在左边还是右边,再进行一次判断
if (parent->_key < key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
//**********解决方法*********
void Inorder()
{
_Inorder(_root);
}
void _Inorder(Node* root) //中序
{
if (root == nullptr) //空树直接返回
{
return;
}
_Inorder(root->_left); //先走左,再走根,后走右
cout << root->_key << " ";
_Inorder(root->_right);
}
//***************************
bool Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
cur = cur->_right;
}
else if (cur->_key > key)
{
cur = cur->_left;
}
else
{
return true;
}
}
return false;
}
private:
Node* _root;
};
void TestBSTree()
{
BSTree<int> t;
int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
for (auto e : a)
{
t.Insert(e);
}
//t._Inorder();//无法调用,调用需要根,但根私有,拿不到
//解决方案,写一个子函数
t.Inorder();
}
main.c
#include <iostream>
#include "BinarySerchTree.h"
using namespace std;
int main()
{
TestBSTree();
return 0;
}
1.0 插入
默认情况下不允许冗余,插入5(5本身已经存在,)故插入会返回FALSE。
- 空树 直接插入
- 非空树
bool Insert(const K& key)
{
if (_root == nullptr) //空树
{
_root = new Node(key);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key < key) //比你大,往右走
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else //相等则说明,值已经存在
{
return false;
}
}
cur = new Node(key);
//链接在左边还是右边,再进行一次判断
if (parent->_key < key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
2.0 走中序 (排序+去重)
//**********解决方法*********
void Inorder()
{
_Inorder(_root);
}
void _Inorder(Node* root) //中序
{
if (root == nullptr) //空树直接返回
{
return;
}
_Inorder(root->_left); //先走左,再走根,后走右
cout << root->_key << " ";
_Inorder(root->_right);
}
3.0 查找
bool Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
cur = cur->_right;
}
else if (cur->_key > key)
{
cur = cur->_left;
}
else
{
return true;
}
}
return false;
}
4.0 删除
1.没有孩子的节点
2.只有一个孩子的节点 (1.2合成一个情况,直接删除)
3.有两个孩子的节点 (替换法删除,左子树的最大的节点或者右子树的最小节点,进行替换 )
第一种情况:直接删除:
删除8:左为空(被删除),让父亲的右指向我的右
删除1:左为空,让父亲的左指向我的右
讨论父亲左为空的情况,1)父亲的右指向我的右,2)父亲的左指向我的
左为空,如果父亲被干掉,则让右树为新的根。同理,右也相同。
if (parent == nullptr)
{
_root = cur->_right;
}
父亲是空情况(只有一个节点)左为空,则右孩子的根则为新的根,
右为空,则左孩子的根为新的根
if (cur->_left == nullptr)//如果我的左为空
{
if (parent == nullptr)
{
_root = cur->_right;
}
else
{
if (parent->_left == cur) //如果我是父亲的左,父亲的左指向我的右
parent->_left = cur->_right;
else
parent->_right = cur->_right; //否则父亲的右指向我的右
}
delete cur;
}
else if (cur->_right == nullptr) //如果我的右为空
{
if (parent == nullptr) //要对父亲为空进行判断
{
_root = cur->_left;
}
else
{
if (parent->_left == cur)
parent->_left = cur->_left;
else
parent->_right = cur->_left;
}
delete cur;
}
左右都不为空
else //左右都不为空
{
Node* minParent = cur; //找右树的最左节点
Node* min = cur->_right;
while (min->_left)
{
minParent = min; //min往下走,min给parent
min = min->_left;
}
cur->_key = min->_key; //把min的值覆盖过去,然后要把min删除(需要找min的父亲)
if (minParent->_left == min) //minParent有左树
minParent->_left = min->_right; //替换法删除(minParent的左指向他的右)这样就把min删除了
else
minParent->_right = min->_right; //minParent的右指向min的右
delete min; //删除min
}
假设删除5 替换法,找右树的最左节点
用6去覆盖5,然后在删除7的左树6
删除的话,找右树的最左节点。
假设删除7。第二种情况:右子树的根即为最左节点(无最左节点)
else //左右都不为空
{
Node* minParent = cur;
Node* min = cur->_right; //找右树的最左节点
while (min->_left)
{
minParent = min; //min往下走,min给parent
min = min->_left; //找到了右树的最左节点
}
cur->_key = min->_key; //把min的值覆盖过去,然后要把min删除(需要找min的父亲)
//下面为删除min
if (minParent->_left == min) //minParent有左树
minParent->_left = min->_right; //替换法删除(minParent的左指向他的右)这样就把min删除了
else
minParent->_right = min->_right; //minParent的右指向min的右
delete min; //删除min
}
5.0 递归查找
Node* _FindR(Node* root, const K& key)
{
if (root == nullptr)
{
return nullptr;
}
if (root->_key < key)
{
return _FindR(root->_right, key);
}
else if (root->_key > key)
{
return _FindR(root->_left, key);
}
else
{
return root;
}
}
6.0 插入
bool _InsertR(Node*& root, const K& key) //注意此处的Node*& root,引用
{
if (root == nullptr)
{
root = new Node(key); //*********
return true;
}
if (root->_key < key) //大,则递归去右树去查找
return _InsertR(root->_right, key);
else if (root->_key > key)
return _InsertR(root->_left, key);
else //相等,不允许插入
return false;
}
3往下递归,root的值是空,但同时是3的节点的右指针的别名
7.0 搜索树的应用
- 搜索 key搜索模型 key/value搜索模型
- 排序+去重
搜索-> 在不在