数据结构与算法之树

数据结构与算法之树

1.树的定义:
树是由n个结点组成的有限集合,当n=0时称为空树,否则,在任何非空树中:

  • 必有一个特定的称为根的结点;
  • 剩下的结点被分成m>=0个互不相干的集合T1.T2…Tn,而且这些集合的每一个又都是树。树T1.T2…Tn被称为根的子树。

树的基本术语
在这里插入图片描述
叶子:终端结点
根:非终端节点
有序树:结点的各子树从左到右是有次序的
结点的度:结点拥有的子树数
树的度:各节点度的最大值
在这里插入图片描述

结点所处的层次即为结点深度;
树中结点的最大层次即为树的深度;

2.二叉树
二叉树:所有结点的度都小于等于2。

  • 二叉树的子树有左右之分,即使只有一颗子树也应分清左右
  • 满二叉树:深度为k,结点数为2的k次方减一
  • 完全二叉树:所有结点对应于其相同深度的满二叉树中的位序

以下将用 c++ 实现二叉树数组和二叉树链表
2.1二叉树数组

//关于数组和树之间的算法转换

int tree[]={3,5,8,2,6,9,7}  

           3(0)                //父节点下标*2+1=左孩子
	                           //父节点下标*2+1=右孩子
	5(1)         8(2)

2(3)  6(4)     9(5)  7(6)  

二叉树数组代码实现:
tree.h

#ifndef TREE_H
#define TREE_H

class Tree
{
public:
	Tree(int size, int *pRoot);                            //创建树
	~Tree();                                               //销毁树
	int *SearchNode(int nodeIndex);                        //根据索引寻找结点
	bool AddNode(int nodeIndex, int direction, int *pNode);//添加结点
	bool DeleteNode(int nodeIndex, int *pNode);            //删除结点
	void TreeTraverse();                                   //遍历结点
private:
	int *m_pTree;
	int m_iSize;
};

#endif

tree.cpp

#include<iostream>
#include"tree.h"
using namespace std;

Tree::Tree(int size, int *pRoot)
{
	m_iSize = size;
	m_pTree = new int[size];
	for (int i = 0; i < size; i++)
		*(m_pTree + i) = 0;
	*m_pTree = *pRoot;//初始化根结点
}

Tree::~Tree()
{
	delete m_pTree;
	m_pTree = NULL;
}

//寻找结点
int *Tree::SearchNode(int nodeIndex)
{
	if (nodeIndex < 0 || nodeIndex >= m_iSize)
		return NULL;
	if (*(m_pTree + nodeIndex) == 0)
		return NULL;
	return m_pTree + nodeIndex;
}

//添加结点
bool Tree::AddNode(int nodeIndex, int direction, int *pNode)//通过父节点插入,direction=0表示插入左孩子,direction=1表示右孩子
{
	if (nodeIndex < 0 || nodeIndex >= m_iSize)
		return false;
	if (*(m_pTree + nodeIndex) == 0)
		return false;       //若等于0,则表示该父节点不存在

	if (direction == 0)
	{
		if (nodeIndex * 2 + 1 >= m_iSize)
			return false;  
		if (*(m_pTree + nodeIndex * 2 + 1) != 0)
			return false;  //若其不等于0,则表示这个地方已经有子结点了
		*(m_pTree + nodeIndex * 2 + 1) = *pNode;
	}

	if (direction == 1)
	{
		if (nodeIndex * 2 + 2 >= m_iSize)
			return false;
		if (*(m_pTree + nodeIndex * 2 + 2) != 0)
			return false;  //若其不等于0,则表示这个地方已经有子结点了
		*(m_pTree + nodeIndex * 2 + 2) = *pNode;
	}
	return true;
}

//删除结点
bool Tree::DeleteNode(int nodeIndex, int *pNode)
{
	if (nodeIndex < 0 || nodeIndex >= m_iSize)
		return false;
	if (*(m_pTree + nodeIndex) == 0)
		return false;       
	*pNode = *(m_pTree + nodeIndex); 
	*(m_pTree + nodeIndex) = 0;//将该结点置为0(删掉)
	return true;
}

void Tree::TreeTraverse()
{
	for (int i = 0; i < m_iSize; i++)
		cout << *(m_pTree + i) << " ";
}

main.cpp

#include<iostream>
#include"tree.h"
using namespace std;

int main(void)
{
	/*测试
	int root = 3;
	Tree *p = new Tree(10,&root);
	int n1 = 5, n2 = 8, n3 = 2, 
		n4 = 6, n5 = 9, n6 = 7;
	p->AddNode(0, 0, &n1);
	p->AddNode(0, 1, &n2);
	p->AddNode(1, 0, &n3);
	p->AddNode(1, 1, &n4);
	p->AddNode(2, 0, &n5);
	p->AddNode(2, 1, &n6);
	p->TreeTraverse();
	cout << "\n";
	cout << *(p->SearchNode(2)) << endl;
	int n8;
	p->DeleteNode(3, &n8);
	cout << n8 << endl;
	p->TreeTraverse();

	delete p;
	p = NULL;*/

	system("pause");
	return 0;
}

2.1二叉树链表

           3(0)                
					           
	5(1)         8(2)

2(3)  6(4)     9(5)  7(6)

递归定义!!!
//先根序遍历(根左右)  0 1 3 4 2 5 6
//中根序遍历(左根右)  3 1 4 0 5 2 6
//后根序遍历(左右根)  3 4 1 5 6 2 0
  • 二叉树链表中,若删除一个结点,则该结点以及该结点的孩子结点都将被删除
    二叉树链表代码实现:
    node.h
#ifndef NODE_H
#define NODE_H

#include<iostream>
class Node
{
public:
	Node();
	Node *SearchNode(int nodeIndex);
	void DeleteNode();
	void PreorderTraverse();
	void InorderTraverse();                               
	void PostorderTraverse();
	int index;//位序
	int data;
	Node *pLChild;//左孩子指针
	Node *pRChild;//右孩子指针
	Node *pParent;//父节点指针
};

#endif

node.cpp

#include<iostream>
#include"node.h"
using namespace std;

Node::Node()
{
	index = 0;
	data = 0;
	pLChild = NULL;
	pRChild = NULL;
	pParent = NULL;
}

Node *Node::SearchNode(int nodeIndex)
{
	Node *temp = NULL;
	if (this->index == nodeIndex)
		return this;

	if (this->pLChild != NULL)
	{
		if (this->pLChild->index == nodeIndex)
			return this->pLChild;
		else
		{
			temp = this->pLChild->SearchNode(nodeIndex);
			if (temp != NULL)
				return temp;
		}
	}

	if (this->pRChild != NULL)
	{
		if (this->pRChild->index == nodeIndex)
			return this->pRChild;
		else
		{
			temp = this->pRChild->SearchNode(nodeIndex);
			if (temp != NULL)
				return temp;
		}
	}

	return NULL;
}

void Node::DeleteNode() //递归实现,将该结点以及从该结点衍生出的所有子孙全部释放
{
	if (this->pLChild != NULL)
	{
		this->pLChild->DeleteNode();
	}
	if (this->pRChild != NULL)
	{
		this->pRChild->DeleteNode();
	}

	if (this->pParent != NULL)
	{
		if (this->pParent->pLChild == this)
			this->pParent->pLChild = NULL;
		if (this->pParent->pRChild == this)
			this->pParent->pRChild = NULL;
	}

	delete this;//注意:左右子结点都通过递归函数调用了delete this
}

void Node::PreorderTraverse()
{
	cout << this->index << "   " << this->data << endl;

	if (this->pLChild != NULL)
		this->pLChild->PreorderTraverse();

	if (this->pRChild != NULL)
		this->pRChild->PreorderTraverse();
}

void Node::InorderTraverse()
{
	if (this->pLChild != NULL)
		this->pLChild->InorderTraverse();

	cout << this->index << "   " << this->data << endl;

	if (this->pRChild != NULL)
		this->pRChild->InorderTraverse();
}

void Node::PostorderTraverse()
{
	if (this->pLChild != NULL)
		this->pLChild->PostorderTraverse();

	if (this->pRChild != NULL)
		this->pRChild->PostorderTraverse();

	cout << this->index << "   " << this->data << endl;
}

tree.h

#ifndef TREE_H
#define TREE_H
#include"node.h"
class Tree
{
public:
	Tree();                                                 //创建树
	~Tree();                                                //销毁树
	Node *SearchNode(int nodeIndex);                        //根据索引寻找结点
	bool AddNode(int nodeIndex, int direction, Node *pNode);//添加结点
	bool DeleteNode(int nodeIndex, Node *pNode);            //删除结点
	void PreorderTraverse();                                //先根序遍历
	void InorderTraverse();                                 //中根序遍历
	void PostorderTraverse();                               //后根序遍历
private:
	Node *m_pRoot;
};

#endif

tree.cpp

#include<iostream>
#include"tree.h"
#include"node.h"

Tree::Tree()
{
	m_pRoot = new Node(); 
}

Tree::~Tree()
{
	DeleteNode(0, NULL);
}

Node *Tree::SearchNode(int nodeIndex)
{
	return m_pRoot->SearchNode(nodeIndex);
}

bool Tree::AddNode(int nodeIndex, int direction, Node *pNode)
{
	Node *temp = SearchNode(nodeIndex);
	if (temp == NULL)
		return false;

	Node *node = new Node();       //申请一块内存来存放新的结点信息,而不能直接将父节点的孩子指针指向pNode
	if (node == NULL)
		return false;
	node->index = pNode->index;
	node->data = pNode->data;
	node->pParent = temp;

	if (direction == 0)
		temp->pLChild = node;
	if (direction == 1)
		temp->pRChild = node;
	return true;
}

bool Tree::DeleteNode(int nodeIndex, Node *pNode)
{
	Node *temp = SearchNode(nodeIndex);
	if (temp == NULL)
		return false;

	if (pNode != NULL)
		pNode->data = temp->data;

	temp->DeleteNode();
	return true;
}

void Tree::PreorderTraverse()
{
	m_pRoot->PreorderTraverse();
}

void Tree::InorderTraverse()
{
	m_pRoot->InorderTraverse();
}

void Tree::PostorderTraverse()
{
	m_pRoot->PostorderTraverse();
}

main.cpp

#include<iostream>
#include"tree.h"
using namespace std;

int main(void)
{
	//Node *n1 = new Node();
	//n1->data = 5;
	//n1->index = 1;	

	//Node *n2 = new Node();
	//n2->data = 8;
	//n2->index = 2;

	//Node *n3 = new Node();
	//n3->data = 2;
	//n3->index = 3;

	//Node *n4 = new Node();
	//n4->data = 6;
	//n4->index = 4;

	//Node *n5 = new Node();
	//n5->data = 9;
	//n5->index = 5;

	//Node *n6 = new Node();
	//n6->data = 7;
	//n6->index = 6;

	//Tree *tree = new Tree();
	//tree->AddNode(0, 0, n1);
	//tree->AddNode(0, 1, n2);
	//tree->AddNode(1, 0, n3);
	//tree->AddNode(1, 1, n4);
	//tree->AddNode(2, 0, n5);
	//tree->AddNode(2, 1, n6);
	tree->PreorderTraverse();
	///*tree->InorderTraverse();
	//tree->PostorderTraverse();*/
	//tree->DeleteNode(2, NULL);
	//tree->PreorderTraverse();

	delete tree;
	tree = NULL;

	system("pause");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值