有序二叉树的删除与遍历

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 << " ";
	
}

猜你喜欢

转载自blog.csdn.net/appup/article/details/115510882