数据结构学习第十六课(有序二叉树)

有序二叉树

1,头文件
#pragma once
template<typename T>
class MyTree
{
private:
	struct Node
	{
		T data;//数据
		Node* pLeft;//指向左孩子
		Node* pRight;//指向右孩子
	};
	Node* pRoot;//指向树根
public:
	MyTree();
	~MyTree();

	void insertNode(const T& data);//插入一个节点到树中
	void travel();//遍历
	//已知顺序推导树结构
	//已知 先序和中序 能推导出 树的形状
	//已知 中序和后序 能推导出 树的形状
	//已知 先序和后序 不能推导出 树的形状
	void deleteNode(const T& data);//删除
	/*
	1,找到要删除的节点,如果找不到直接结束;
	2 找到了,判断要删除的节点是否为根结点
	 2.1是根结点
	    2.1.1 有右孩子
		      让根结点的左孩子成为 根结点的右孩子的最左孩子;
			  删掉根结点
			  让根结点的右孩子成为根结点
        2.1.2 没有右孩子
		      删掉根结点
			  让根结点的左孩子成为根结点
      2.2不是根结点
	    2.2.1 找到要删除的节点(pDelete)的父结点(pDelParent)
		2.2.2 要删除的节点是其父结点的左孩子
		 2.2.2.1 pDelete有右孩子
		         让PDelete的左孩子成为PDelete的右孩子的最左孩子
				 删除PDelete
				 pDelete的右孩子成为PDelParent的左孩子
		 2.2.2.1 pDelete没有右孩子
				 删除PDelete
				 pDelete的左孩子成为PDelParent的左孩子
		2.2.3  要删除的节点是其父结点的右孩子
		 2.2.3.1 pDelete有右孩子
		         让PDelete的左孩子成为PDelete的右孩子的最左孩子
				 删除PDelete
				 pDelete的右孩子成为PDelParent的右孩子
		 2.2.3.1 pDelete没有右孩子
				 删除PDelete
				 pDelete的左孩子成为PDelParent的右孩子
	
	*/
private:
	void _preTravel(Node* pRoot);
	void _midTravel(Node* pRoot);
	void _lstTravel(Node* pRoot);
	Node* _createNode(const T& data)
	{
		Node* pNew = new Node;
		pNew->data = data;
		pNew->pLeft = pNew->pRight = NULL;
		return pNew;
	}

	//插入一个节点到树中
	void _insertNode(Node** root, const T& data);
	void _insertNode(Node*& root, const T& data);
	//从树中找某个节点,找到返回节点地址,否则返回NULL
	Node* _findNode(Node* root, const T& data);
};

template<typename T>
inline MyTree<T>::MyTree()
{
	pRoot = NULL;
}

template<typename T>
inline MyTree<T>::~MyTree()
{

}

template<typename T>
inline void MyTree<T>::insertNode(const T& data)
{
	//_insertNode(&pRoot, data);
	_insertNode(pRoot,data);
}

template<typename T>
inline void MyTree<T>::travel()
{
	//先序 : 根 左 右
	printf("先序:");
	_preTravel(pRoot);
	//中序 : 左 根 右 
	printf("\n");
	printf("中序:");
	_midTravel(pRoot);
	//后序 : 左 右 根
	printf("\n");
	printf("后序:");
	_lstTravel(pRoot);
}

template<typename T>
inline void MyTree<T>::deleteNode(const T& data)
{
	//1 找到删除的节点
	Node* pDelete = _findNode(pRoot, data);
	if (pDelete)
	{
		printf("找到了%d\n", pDelete->data);
	}
	else
	{
		printf("没找到\n");
	}
	Node* pTemp = NULL;
	Node* pBuff = NULL;
	//2 判断是否为根结点
	if (pRoot == pDelete)//2.1 是根结点
	{
		if (pRoot->pRight)//2.1.1 有右孩子
		{
			//找到根结点的右孩子的最左孩子;
			pBuff=pTemp = pRoot->pRight;
			while (pTemp->pLeft)
			{
				pTemp = pTemp->pLeft;
			}
			// 让根结点的左孩子成为 根结点的右孩子的最左孩子;
			pTemp->pLeft = pRoot->pLeft;
			//删掉根结点
			delete pRoot;
			//让根结点的右孩子成为根结点
			pRoot = pBuff;
		}
		else//2.1.2 没有右孩子
		{
			pBuff = pRoot->pLeft;
			//删掉根结点
			delete pRoot;
			//让根结点的左孩子成为根结点
			pRoot = pBuff;
		}
		return;
	}
	// 2.2不是根结点
	//2.2.1 找到要删除的节点(pDelete)的父结点(pDelParent)
	Node* pDelParent = NULL;
	pDelete = pRoot;
	while (pDelete)
	{
		if (data == pDelete->data)
		{
			break;
		}
		pDelParent = pDelete;
		if (data > pDelete->data)
		{
			pDelete = pDelete->pRight;
		}
		else
		{
			pDelete = pDelete->pLeft;
		}
	}
	printf("要删除的:%d ,父结点: %d\n", pDelete->data, pDelParent->data);

	if (pDelete == pDelParent->pLeft)//2.2.2 要删除的节点是其父结点的左孩子
	{
		if (pDelete->pRight)//2.2.2.1 pDelete有右孩子
		{
			//找到PDelete的右孩子的最左孩子
			pBuff= pTemp = pDelete->pRight;
			while (pTemp->pLeft)
			{
				pTemp = pTemp->pLeft;
			}
			//让PDelete的左孩子成为PDelete的右孩子的最左孩子
			pTemp->pLeft = pDelete->pLeft;
			//删除PDelete
			delete pDelete;
			//pDelete的右孩子成为PDelParent的左孩子
			pDelParent->pLeft = pBuff;
		}
		else//2.2.2.2 pDelete没有右孩子
		{
			pBuff = pDelete->pLeft;
			//删除PDelete
			delete pDelete;
			//pDelete的左孩子成为PDelParent的左孩子
			pDelParent->pLeft = pBuff;
		}
	}
	else//2.2.3  要删除的节点是其父结点的右孩子
	{
		if (pDelete->pRight)//	2.2.3.1 pDelete有右孩子
		{
			//找到PDelete的右孩子的最左孩子
			pBuff = pTemp = pDelete->pRight;
			while (pTemp->pLeft)
			{
				pTemp = pTemp->pLeft;
			}
			//让PDelete的左孩子成为PDelete的右孩子的最左孩子
			pTemp->pLeft = pDelete->pLeft;
			//删除PDelete
			delete pDelete;
			//pDelete的右孩子成为PDelParent的右孩子
			pDelParent->pRight = pBuff;
		}
		else//	2.2.3.1 pDelete没有右孩子
		{
			pBuff = pDelete->pLeft;
			//删除PDelete
			delete pDelete;
			//	pDelete的左孩子成为PDelParent的右孩子
			pDelParent->pRight = pBuff;
		}	
	}
	
}
template<typename T>
inline void MyTree<T>::_preTravel(Node* pRoot)
{
	if (NULL == pRoot)
	{
		return;
	}
	printf("%d ", pRoot->data);//根
	_preTravel(pRoot->pLeft);//左
	_preTravel(pRoot->pRight);//右
}

template<typename T>
inline void MyTree<T>::_midTravel(Node* pRoot)
{
	if (NULL == pRoot)
	{
		return;
	}
	_midTravel(pRoot->pLeft);//左
	printf("%d ", pRoot->data);//根
	_midTravel(pRoot->pRight);//右
}


template<typename T>
inline void MyTree<T>::_lstTravel(Node* pRoot)
{
	if (NULL == pRoot)
	{
		return;
	}
	_lstTravel(pRoot->pLeft);//左
	_lstTravel(pRoot->pRight);//右
	printf("%d ", pRoot->data);//根
}

template<typename T>
inline void MyTree<T>::_insertNode(Node** root, const T& data)
{
	if (NULL == *root)
	{
		*root = _createNode(data);
		return;
	}
	if ((*root)->data < data)//放右边
	{
		_insertNode(&(*root)->pRight, data);
	}
	else//放左边
	{
		_insertNode(&(*root)->pLeft, data);
	}
}

template<typename T>
inline void MyTree<T>::_insertNode(Node*& root, const T& data)
{
	if (NULL == root)
	{
		root = _createNode(data);
		return;
	}
	if ((root)->data < data)//放右边
	{
		_insertNode(root->pRight, data);
	}
	else//放左边
	{
		_insertNode(root->pLeft, data);
	}
}

template<typename T>
typename MyTree<T>:: Node* MyTree<T>::_findNode(Node* root, const T& data)
{
	Node* pTemp = root;
	while (pTemp)
	{
		if (data == pTemp->data)
		{
			return pTemp;
		}
		if (data > pTemp->data)
		{
			pTemp = pTemp->pRight;
		}
		else
		{
			pTemp = pTemp->pLeft;
		}
	}
	return NULL;
}

2,源文件
/*
1, 有序二叉树
升序: 左<根<右
降序: 左>根>右
2,做一棵有序二叉树
2.1 有序二叉树类
2.2. 插入
2.3 遍历
2.4 删除
*/
#include<stdio.h>
#include"MyTree.h"
int main()
{
	MyTree<int> tree;
	tree.insertNode(3);
	tree.insertNode(8);
	tree.insertNode(6);
	tree.insertNode(2);
	tree.insertNode(1);
	tree.insertNode(7);
	tree.insertNode(9);
	tree.insertNode(66);
	tree.insertNode(55);
	tree.insertNode(34);
	tree.travel();
	int n;
	while (1)
	{
		printf("输入删除的节点:");
		scanf("%d", &n);
		tree.deleteNode(n);
		tree.travel();
	}

	while (1);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值