数据结构与算法之树
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;
}