树: 是 n(n≥0) 个结点的有限集合。如果该集合为空,称为空树。在任意一棵非空树中:
1)有且仅有一个特定的称为根结点 ( root ) 的结点;
2) 其他结点可分为若干个互不相交的子集(递归定义),而且每一个子集本身又是一棵树,称为根的子树。
基本概念:
结点:树的顶点;
结点的度:结点分支的个数,即子树的数目 如:A的度-3;B的度-2;K的度-0;
树的度:树中所有结点的度的最大值 如:树的度为3;
叶子结点:度为零的结点,也称终端结点 如例:K,L,F,G,M,I,J为终端结点
分支结点:度大于0的结点 如例:A,B,C,D,E
根:非终端结点
深度:结点深度:某一层结点的数目
树的深度:树有几层
森林:多棵树放在一起
二叉树
定义:所有结点的度都小于等于2
二叉树的遍历
前序遍历:根在前面访问 左根右
中序遍历:左结点 根 右结点
后序遍历:左结点 右结点 根
树的用途
搜索-人机对战、压缩软件-哈夫曼树
二叉树的表达
数组表示
父亲结点下标*2+1 该结点左
父亲结点下标*2+2 该节点右
int tree[n] 3 5 8 2 6 9 7
3(0)
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.c的代码如下:
#include "Tree.h"
#include <iostream>
using namespace std;
Tree::Tree(int size,int *pRoot)
{
m_pTree = new int[size];
m_iSize = size;
for(int i=0;i<size;++i)
{
m_pTree[i]=0;
}
m_pTree[0]=*pRoot;
}
Tree::~Tree()
{
delete[] m_pTree;
}
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)
{
if(nodeIndex < 0 || nodeIndex >= m_iSize)
{
return NULL;
}
if(m_pTree[nodeIndex]==0)
{
return NULL;
}
if(direction==0)
{
if(nodeIndex * 2 +1 >= m_iSize)
{
return NULL;
}
if(m_pTree[nodeIndex * 2 +1])
{
return NULL;
}
m_pTree[nodeIndex * 2 +1] = *pNode;
}
if(direction==1)
{
if(nodeIndex * 2 +2 >= m_iSize)
{
return NULL;
}
if(m_pTree[nodeIndex * 2 +2])
{
return NULL;
}
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;
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()
{
int root = 3;
Tree *p = new Tree(10,&root);
int node1=5;
int node2=8;
p->AddNode(0,0,&node1);
p->AddNode(0,1,&node2);
int node3=2;
int node4=6;
p->AddNode(1,0,&node3);
p->AddNode(1,1,&node4);
int node5=9;
int node6=7;
p->AddNode(2,0,&node5);
p->AddNode(2,1,&node6);
int node = 0;
p->DeleteNode(5,&node);
cout << endl << "node="<< node << endl;
p->TreeTraverse();
int *p1 = p->SearchNode(2);
cout << *p1 << endl;
delete p;
while(1);
return 0;
}
链表表示
要素:索引、数据、左孩子指针、右孩子指针、父结点指针
结点的数据成员如下,Node.h:
#ifndef NODE_H
#define NODE_H
class Node
{
public:
Node();
Node *SearchNode(int nodeIndex);
//五个数据成员
int index; //结点的索引
int data; //结点的数据 可以是复杂的,也可以是内
Node *pLChild; //做孩子指针 ,都是Node*
Node *pRChild; //右孩子指针
Node *pParent; //父亲结点指针
};
#endif
Node.c文件内容如下:
#include "Node.h"
#include <iostream>
using namespace std;
Node::Node()
{
index = 0;
data = 0;
pLChild = NULL;
pRChild = NULL;
pParent = NULL;
}
Node *Node::SearchNode(int nodeIndex)
{
//判断该结点是否为要搜索的结点
if(this->index = nodeIndex)
{
return this;
}
//判断左边的结点是否为要搜索的结点
if(this->pLChild != NULL)
{
if(this->pLChild->index == nodeIndex)
{
return this->pLChild;
}
}
//判断右边的结点是否为要搜索的结点
if(this->pRChild != NULL)
{
if(this->pRChild->index == nodeIndex)
{
return this->pRChild;
}
}
return NULL;
}
树的类如下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 TreeTraverse(); //遍历结点
void PreorderTraverse(); //前序遍历 根左右
void InorderTraverse(); //中序遍历 左根右
void PostorderTraverse(); //后序遍历 左右根
//结点要素:索引 数据 做孩子指针 右孩子指针(通过头结点找子结点)
private:
Node *m_pRoot;
};
#endif
创建树的函数为Tree();
具体实现方法为:
Tree::Tree()
{
m_pRoot = new Node(); //创建一个根结点
}
销毁树不能只销毁一个m_pRoot指针,先看看如何实现结点的寻找,即Node *SearchNode(int nodeIndex)函数,实现如下,这里不是很理解,继续向下看:
Node* Tree::SearchNode(int nodeIndex)
{
return m_pRoot->SearchNode(nodeIndex);//调用Node的成员函数来寻找结点
}
然后是添加结点函数:bool AddNode(int nodeIndex,int direction,Node *pNode);
bool Tree::AddNode(int nodeIndex,int direction,Node *pNode)
{
Node *temp = this->SearchNode(nodeIndex);
if(temp == NULL)
{
return false;
}
Node *node = new Node();
//判断申请的内存是否失败
if(node == NULL) return false;
node->index = pNode->index;
node->data = pNode->data;
if(direction == 0)
{
temp->pLChild = node;
}
if(direction == 1)
{
temp->pRChild = node;
}
return true;
}
对于删除结点的函数设计比较困难,函数为bool DeleteNode(int nodeIndex,Node *pNode); //删除结点
需要在Node中添加void DeleteNode()函数:
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 != NULL)
{
this->pParent->pLChild = NULL;
}
if(this->pParent->pRChild != NULL)
{
this->pParent->pRChild = NULL;
}
}
delete this;
}
课程要求
完成树的基本操作:
1.树的创建与销毁;
2.树中结点的搜索;
3.树中结点的添加与删除;
4.树中结点的遍历