树,是有限节点的集合。生活中的树是树根在下面,数据结构中的树的根在顶部,如下图:
公司的人员组织架构,董事长,总经理,副总。。。,这种模型可以用二叉树表示,还有一些压缩算法也用到了树结构。
树的几个概念
(1)度:有几个直接的孩子,例如,A的度是3,它有BCD三个孩子,B的度是2,它有EF两个孩子,度为0的节点也就是叶子节点(终端节点)
(2)祖先:E的祖先是B,A , 从当前节点一直往上找
(3)叶子节点:下面的一层称为叶子节点,也可以称为终端节点。
(4)根:非叶子节点。
(5)树的深度,如下图
(6)森林:不交叉的几棵树在一起称为森林
二叉树
所有节点的度都小于等于2的树称为二叉树。下面这几种都可以称为二叉树
1、二叉树的遍历
3种遍历方式,根据根节点的位置,分为前序,中序,后序。
前序:根左右,ABC
中序 :左根右, BAC
后序遍历:左右根, BCA
例如下面这颗二叉树
从根节点A在结果中的位置也可以看出是那种遍历方式。
2、二叉树的存储结构
(1)顺序存储,类似于数组,例如下面这颗二叉树,在数组中的存储是:3561972
数组存储时,如果节点不存在就用0表示,例如下面的,在数组中就是35019
顺序存储可以作为一种特殊形式,有相关需求时可以采用,
(2)链式存储,这是二叉树最好的存储形式,用一个结构体表示节点,有数据成员,指向左子树的指针,指向右子树的指针。
3、满二叉树与完全二叉树
完全二叉树的定义:如果二叉树的深度为h, 除h层外,其它各层的节点数都达到最大数,且第h层的所有节点都连续集中在最左边,这种二叉树称为完全二叉树。
C++实现二叉树
下面介绍如何用数组和链表,例如实现下面这颗树
基于数组的二叉树实现
头文件TreeArray.h
/*
用数组实现二叉树
*/
#pragma once
//节点的插入方向
enum DIRECTION
{
LEFT,
RIGHT
};
class TreeArray
{
public:
TreeArray(int size, int *pRoot); //构造创建树
~TreeArray(); //销毁树
int *SearchNode(int nodeIndex);
bool AddNode(int nodeIndex, DIRECTION dirc, int *pNode);
bool DeleteNode(int nodeIndex, int *pNode);
void TreeTraverse(); //遍历树
private:
int *m_pTree;
int m_iSize; //树的容量
};
TreeArray.cpp
#include "TreeArray.h"
#include <iostream>
using namespace std;
TreeArray::TreeArray(int size,int *pRoot)
{
if (size > 0)
{
m_iSize = size;
m_pTree = new int[size];
for (int i = 0; i < size; i++)
{
m_pTree[i] = 0;
}
m_pTree[0] = *pRoot;
}
else
{
m_iSize = 0;
m_pTree = nullptr;
}
}
TreeArray::~TreeArray()
{
if (m_pTree != nullptr)
{
delete[] m_pTree;
m_pTree = nullptr;
}
}
int * TreeArray::SearchNode(int nodeIndex)
{
if (nodeIndex < m_iSize && m_pTree >= 0)
{
if (m_pTree[nodeIndex] == 0) //0表示空节点
{
return nullptr;
}
}
else
{
return nullptr;
}
return &m_pTree[nodeIndex];
}
bool TreeArray::AddNode(int nodeIndex, DIRECTION dirc, int * pNode)
{
if (nodeIndex < 0 || nodeIndex >= m_iSize)
{
return false;
}
if (m_pTree[nodeIndex] == 0)
{
return false;
}
if (dirc == LEFT)
{
int insertId = nodeIndex * 2 + 1;
if (insertId >= m_iSize)
{
return false;
}
if (m_pTree[insertId] != 0)
{
return false;
}
m_pTree[insertId] = *pNode;
}
else if (dirc == RIGHT)
{
int insertId = nodeIndex * 2 + 2;
if (insertId >= m_iSize)
{
return false;
}
if (m_pTree[insertId] != 0)
{
return false;
}
m_pTree[insertId] = *pNode;
}
return true;
}
bool TreeArray::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 TreeArray::TreeTraverse()
{
for (int i = 0; i<m_iSize; i++)
{
cout << m_pTree[i] << " ";
}
cout << endl;
}
main函数测试
#include <iostream>
#include "TreeArray.h"
using namespace std;
int main()
{
int root = 666;
TreeArray *pTree = new TreeArray(10, &root);
int node1 = 500;
int node2 = 800;
pTree->AddNode(0, LEFT, &node1);
pTree->AddNode(0, RIGHT, &node2);
int node3 = 200;
int node4 = 600;
pTree->AddNode(1, LEFT, &node3);
pTree->AddNode(1, RIGHT, &node4);
int node5 = 900;
int node6 = 700;
pTree->AddNode(2, LEFT, &node5);
pTree->AddNode(2, RIGHT, &node6);
//遍历
pTree->TreeTraverse();
//查找
int *pValue = pTree->SearchNode(3);
cout << "index = 3的节点值是" << *pValue << endl;
//删除
int dValue = 0;
pTree->DeleteNode(6, &dValue);
//遍历
pTree->TreeTraverse();
delete pTree;
return 0;
}
运行结果
基于链表的二叉树实现
用链表实现二叉树,得先定义好二叉树的节点类型,根据二叉树的性质,节点得有5个属性:索引、数据 、左孩子指针、右孩子指针 、父结点指针 。如下所示:
struct Node
{
int index;
int data;
Node *pLChild; //左子树
Node *pRChild; //右字数
Node *pParent; //父节点
};
还得实现3种遍历方式,使用递归遍历是比较方便的。具体代码如下
Tree.h
#ifndef TREE_H
#define TREE_H
#include <iostream>
using namespace std;
//树的节点
struct Node
{
Node(int _data = 0);
Node *SearchNode(int nodeIndex);
void DeleteNode();
void PreOrderTraversal();
void MiddleOrderTraversal();
void LastOrderTraversal();
int index;
int data;
Node *pLChild; //左子树
Node *pRChild; //右字数
Node *pParent; //父节点
};
//节点的插入方向
enum DIRECTION
{
LEFT,
RIGHT
};
//二叉树
class Tree
{
public:
Tree(int data = 0); //创建树
~Tree(); //销毁树
Node *SearchNode(int nodeIndex); //搜索结点
bool AddNode(int nodeIndex, DIRECTION direction, Node *pNode); //添加结点
bool DeleteNode(int nodeIndex, Node *pNode); //删除结点
void PreOrderTraversal(); //前序遍历
void MiddleOrderTraversal(); //中序遍历
void LastOrderTraversal(); //后序遍历
private:
Node *m_pRoot;
};
#endif
Tree.cpp
#include "Tree.h"
Node::Node(int _data)
{
index = 0;
data = _data;
pLChild = NULL;
pRChild = NULL;
pParent = NULL;
}
Node *Node::SearchNode(int nodeIndex)
{
if (this->index == nodeIndex)
{
return this;
}
Node *temp = NULL;
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;
}
void Node::PreOrderTraversal()
{
cout << this->index << " " << this->data << endl;
if (this->pLChild != NULL)
{
this->pLChild->PreOrderTraversal();
}
if (this->pRChild != NULL)
{
this->pRChild->PreOrderTraversal();
}
}
void Node::MiddleOrderTraversal()
{
if (this->pLChild != NULL)
{
this->pLChild->MiddleOrderTraversal();
}
cout << this->index << " " << this->data << endl;
if (this->pRChild != NULL)
{
this->pRChild->MiddleOrderTraversal();
}
}
void Node::LastOrderTraversal()
{
if (this->pLChild != NULL)
{
this->pLChild->LastOrderTraversal();
}
if (this->pRChild != NULL)
{
this->pRChild->LastOrderTraversal();
}
cout << this->index << " " << this->data << endl;
}
Tree::Tree(int data)
{
m_pRoot = new Node(data);
}
Tree::~Tree()
{
//DeleteNode(0, NULL);
m_pRoot->DeleteNode();
}
Node *Tree::SearchNode(int nodeIndex)
{
return m_pRoot->SearchNode(nodeIndex);
}
bool Tree::AddNode(int nodeIndex, DIRECTION direction, Node *pNode)
{
Node *temp = SearchNode(nodeIndex);
if(temp == NULL)
{
return false;
}
Node *node = new Node();
if(node == NULL)
{
return false;
}
node->index = pNode->index;
node->data = pNode->data;
node->pParent = temp;
if(direction == LEFT)
{
temp->pLChild = node;
}
if(direction == RIGHT)
{
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::PreOrderTraversal()
{
m_pRoot->PreOrderTraversal();
}
void Tree::MiddleOrderTraversal()
{
m_pRoot->MiddleOrderTraversal();
}
void Tree::LastOrderTraversal()
{
m_pRoot->LastOrderTraversal();
}
main方法测试:
#include <iostream>
#include "Tree.h"
int main(void)
{
Node *node1 = new Node();
node1->index = 1;
node1->data = 500;
Node *node2 = new Node();
node2->index = 2;
node2->data = 800;
Node *node3 = new Node();
node3->index = 3;
node3->data = 200;
Node *node4 = new Node();
node4->index = 4;
node4->data = 600;
Node *node5 = new Node();
node5->index = 5;
node5->data = 900;
Node *node6 = new Node();
node6->index = 6;
node6->data = 700;
Tree *tree = new Tree(666);
tree->AddNode(0, LEFT, node1);
tree->AddNode(0, RIGHT, node2);
tree->AddNode(1, LEFT, node3);
tree->AddNode(1, RIGHT, node4);
tree->AddNode(2, LEFT, node5);
tree->AddNode(2, RIGHT, node6);
//tree->DeleteNode(6, NULL);
//tree->DeleteNode(5, NULL);
tree->DeleteNode(2, NULL);
tree->PreOrderTraversal();
//tree->MiddleOrderTraversal();
//tree->LastOrderTraversal();
delete tree;
system("pause");
return 0;
}
以上就是二叉树的两种实现方,推荐使用链表的形式。