1、二叉树的删除
删除有序二叉树节点的时候需要注意,删除以后还是有序的。我这里遵循的是:左>根>右!!!
二叉的删除分为三种情况分析,整体思路为:
1)被删除的节点没有孩子
没有孩子的情况最好分析,直接删除该节点,不会影响二叉树的顺序,删除后其还是有序的。
2)被删除的节点有一个孩子(左孩子或者右孩子)
需要寻找到被删除节点的父节点,将被删除节点的孩子与其父节点连接。
3)被删除的节点有2个孩子
需要找到被删除节点的父节点,以及整颗树中最小的节点。将最小的节点与被删除的节点进行数据互换,然后删除最小节点。
2、二叉树的遍历方式
主要有四种,分别是:前序、中序、后序、层级遍历。程序中实现的是前三种,程序中的树如下:
三种遍历方式的结果是:
1、前序遍历:根、左、右,先根节点,接着左节点,最后右节点。其结果为:45 90 99 91 87 55 77 23 35 14
2、中序遍历:左、 根、右。
结果为:99 91 90 87 77 55 45 35 23 14
3、后序遍历: 左、右、根。
结果为:91 99 77 55 87 90 35 14 23 45
需要的注意的是:所谓前、中、后是基于根节点来说的。
说明:层级遍历遵循从上到下,从左都右。
程序如下:
1).cpp文件
#include "stdafx.h"
#include"BinaryTree.h"
int _tmain(int argc, _TCHAR* argv[])
{
BinaryTree<int>tree;
tree.InsertNode(45);
tree.InsertNode(23);
tree.InsertNode(90);
tree.InsertNode(87);
tree.InsertNode(14);
tree.InsertNode(99);
tree.InsertNode(35);
tree.InsertNode(55);
tree.InsertNode(77);
tree.InsertNode(91);
tree.TravelNode(1);
tree.TravelNode(0);
tree.TravelNode(2);
return 0;
}
2).h文件
#pragma once
#include<memory>
template<class T>
class BinaryTree
{
struct TreeNode
{
T data;//节点数据
TreeNode* pleftChild;//左子节点
TreeNode* prightChild;//右子节点
};
public:
BinaryTree();
~BinaryTree();
void InsertNode(const T&insertData);//插入节点
void deleteNode(const T&delData);
TreeNode* findNode(const T&findData);
TreeNode* findMinNode();
void TravelNode(int travelType);
private:
void _InsertNode(TreeNode**root, const T&insertDara);
void _deleteNode(TreeNode** root, const T&delData);
TreeNode* _findParentNode(const T&findData);
TreeNode* _findMinNode(TreeNode*root);
TreeNode* pRoot;//根节点
void _MidTravel(TreeNode* root);
void _PreTravel(TreeNode* root);
void _LstTravel(TreeNode* root);
};
template<class T>
BinaryTree<T>::BinaryTree()
{
pRoot = NULL;
}
template<class T>
BinaryTree<T>::~BinaryTree()
{
}
template<class T>
void BinaryTree<T>::InsertNode(const T&insertData)
{
_InsertNode(&pRoot, insertData);
}
template<class T>
void BinaryTree<T>::_InsertNode(TreeNode** pNode,const T& insertData)
{
TreeNode *root = *pNode;
if (!root)//当前节点不存在,为空
{
TreeNode* pNewNode = new TreeNode;//开辟一块新内存
memset(pNewNode, 0x00, sizeof(TreeNode));//将新节点中数据置为0
pNewNode->data = insertData;//将需要插入的数据作为新节点的数据
*pNode = pNewNode;//将新节点与树连接起来
}
else//当前节点不为空
{
if (insertData>root->data)//大于在左子树
{
_InsertNode(&(root->pleftChild), insertData);
}
if (insertData<root->data)//小于在右子树
{
_InsertNode(&(root->prightChild), insertData);
}
}
}
template<class T>
void BinaryTree<T>::deleteNode(const T&delData)
{
return _deleteNode(pRoot, delData);
}
template<class T>
void BinaryTree<T>::_deleteNode(TreeNode** root, const T&delData)
{
if (root==0)
return;
TreeNode* pdelNode = findNode(delData);
if (!pdelNode)
return;
TreeNode* pParentNode = _findParentNode(delData);
/*
分为三种情况:
1、要删除的节点没有孩子 没有孩子的找需要删除节点的父节点,并将其孩子删掉
2、要删除的节点有1个孩子 首先要找到需要删除的父节点。
分为2种情况分析:
(1)需要删除的节点是父节点左孩子,则被删除节点的孩子作为其父节点的某一个孩子
(2)需要删除的节点是父节点左孩子,则被删除节点的孩子作为其父节点的某一个孩子
3、要删除的节点有2个孩子
找到右子树中的最小节点,用这个节点替换要删除的节点,然后删除最小节点。
*/
if (pdelNode->pleftChild==0 && pdelNode->prightChild==0)//没有孩子,要删除的节点为叶子结点
{
if (pParentNode->pleftChild==pdelNode)
{
pParentNode->pleftChild = 0;
}
if (pParentNode->prightChild==pdelNode)
{
pParentNode->rightChild = 0;
}
delete pdelNode;
pdelNode = 0;
return;
}
else if (pdelNode->pleftChild==0||pdelNode->rightChild==0)//有一个孩子,左孩子或右孩子
{
if (pParentNode->pleftChild==pdelNode)//当要删除节点为左子节点
{
//将要删除的左节点的左孩子或者右孩子与要删除节点的父节点连接
pParentNode->pleftChild = pdelNode->pleftChild ? pdelNode->pleftChild : pdelNode->prightChild;
}
else
{
//将要删除的右节点的左孩子或者右孩子与要删除节点的父节点连接
pParentNode->prightChild = pdelNode->prightChild ? pdelNode->pleftChild : pdelNode->prightChild;
}
delete pdelNode;
pdelNode = 0;
return;
}
else//有2个孩子,将该子树的最小节点与要删除的节点互换,然后删除需要删除的节点
{
TreeNode* pMinNode = _findMinNode(pdelNode->prightChild);//找到最小节点
TreeNode* pMinNodeParent = _findParentNode(pMinNode->data);//找到最小节点的父节点
pdelNode->data = pMinNode->data;//数据互换
pMinNodeParent->pleftChild = pMinNode->prightChild;//将最小节点作为被删除节点的左孩子
delete pMinNode;
pMinNode = 0;
return;
}
}
//寻找节点
template<class T>
typename BinaryTree<T>::TreeNode* BinaryTree<T>::findNode(const T&findData)
{
TreeNode* pTempNode = pRoot;//将根节点赋值作为当前节点
while (pTempNode)
{
if (pTempNode->data==findData)//找到根节点
{
return pTempNode;
}
if (pTempNode->data>findData)//左子树
{
pTempNode = pTempNode->pleftChild;
}
else//右子树
{
pTempNode = pTempNode->prightChild;
}
}
return 0;
}
//寻找父节点
template<class T>
typename BinaryTree<T>::TreeNode* BinaryTree<T>::_findParentNode(const T&findData)
{
TreeNode* pTempNode = pRoot;//将根节点作为当前节点
TreeNode* pParentNode = pRoot;//根节点是父节点
while (pTempNode)
{
if (pTempNode->data==findData)
{
return pParentNode;//找到该节点,返回父节点
}
pParentNode = pTempNode;//将当前节点为父节点,然后利用左右节点去继续判断
if (pTempNode->data>findData)
{
pTempNode = pTempNode->pleftChild;
}
else
{
pTempNode = pTempNode->prightChild;
}
}
return 0;
}
template<class T>
typename BinaryTree<T>::TreeNode* BinaryTree<T>::_findMinNode(TreeNode*root)
{
if (root)
{
while (root->prightChild)//最小节点只可能在右子树上找到
{
root = root->prightChild;
}
return root;
}
return 0;
}
template<class T>
void BinaryTree<T>::TravelNode(int travelType)
{
if (travelType==0)
{
cout << "中序遍历:";
_MidTravel(pRoot);
cout << endl;
}
if (travelType == 1)
{
cout << "前序遍历:";
_PreTravel(pRoot);
cout << endl;
}
if (travelType == 2)
{
cout << "后序遍历:";
_LstTravel(pRoot);
cout << endl;
}
}
//中序遍历:左、根、右
template<class T>
void BinaryTree<T>::_MidTravel(TreeNode* root)
{
if (root==0)
{
return;
}
_MidTravel(root->pleftChild);
cout << root->data << " ";
_MidTravel(root->prightChild);
}
//前序遍历 根、左、右
template<class T>
void BinaryTree<T>::_PreTravel(TreeNode* root)
{
if (root == 0)
{
return;
}
cout << root->data << " ";
_PreTravel(root->pleftChild);
_PreTravel(root->prightChild);
}
//后序遍历 左、右、根
template<class T>
void BinaryTree<T>::_LstTravel(TreeNode* root)
{
if (root == 0)
{
return;
}
_LstTravel(root->pleftChild);
_LstTravel(root->prightChild);
cout << root->data << " ";
}