树的概念
树是n(n>=0)个有限个数据的元素集合,形状像一颗倒过来的树。
结点:结点包含数据和指向其它结点的指针。
根节点:树第一个结点称为根节点。
结点的度:结点拥有的子节点个数。
叶节点:没有子节点的节点(度为0)。
父子节点:一个节点father指向另一个节点child,则child为孩子节点,father为父亲结点。
兄弟节点:具有相同父节点的节点互为兄弟节点。
节点的祖先:从根节点开始到该节点所经的所有节点都可以称为该节点的祖先。
子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
树的高度:树中距离根节点最远结点的路径长度。
树的存储结构
template <class T>
struct BinaryTreeNode
{
T _data;//用来存数据
BinaryTreeNode* _left;//指向左孩子
BinaryTreeNode* _right;//指向右孩子
BinaryTreeNode(const T& x)
:_data(x)
, _left(NULL)
, _right(NULL)
{}
};
树的应用
树有很多应用,有一种树叫做哈夫曼树,它可以用来压缩存储。平时所保存的文本文件,可以用哈夫曼树进行压缩。
另外一个如图:
二叉树的结构
当处理数据过程中,二叉树的形态和大小不发生剧烈动态变化时,可以采用数组方式表示二叉树抽象数据类型。
用数组方式存储二叉树,就是用连续存储单元存储二叉树数据单元。
二叉树数组表示:
但是当,在一棵树进行删除插入等操作时,可能需要医用很多节点,为了克服这些缺点,用链表来设计出节点。
二叉树
二叉树–> 二叉树是一棵特殊的树,二叉树每个节点最多有两个孩子结点,分别称为左孩子和右孩子。
满二叉树–> 高度为N的满二叉树有2^N - 1个节点的二叉树。
完全二叉树–> 若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树
实现简单二叉树:
#pragma once
#include<iostream>
using namespace std;
#include<queue>
template <class T>
struct BinaryTreeNode
{
T _data;
BinaryTreeNode* _left;
BinaryTreeNode* _right;
BinaryTreeNode(const T& x)
:_data(x)
, _left(NULL)
, _right(NULL)
{}
};
template <class T>
class BinaryTree
{
public:
BinaryTree()
:_root(NULL)
{}
BinaryTree(T* a, size_t size)
{
size_t index = 0;
_root = _CreateTree(a, size, index);
}
~BinaryTree()
{
_Destroy(_root);
_root = NULL;
}
BinaryTree(const BinaryTree<T>& b)
{
_root = _Copy(b._root);
}
BinaryTree<T>& operator=(BinaryTree<T> b)
{
swap(_root, b._root);
return *this;
}
void PrevOrder()
{
_PrevOrder(_root);
cout<<endl;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
void PostOrder()
{
_PostOrder(_root);
cout << endl;
}
void LevelOrder()
{
if (_root != NULL)
{
queue<BinaryTreeNode<int>*> q1;
q1.push(_root);
while (!q1.empty())
{
BinaryTreeNode<int>* front =q1.front();
cout << front->_data<<" ";
q1.pop();//其实是front,但是保存起来了。
if (front->_left)
{
q1.push(front->_left);
}
if (front->_right)
{
q1.push(front->_right);
}
}
cout << endl;
}
}
int Size()
{
int size = 0;
_Size(_root, size);
return size;
}
int Depth()
{
int depth = 0;
depth = _Depth(_root);
return depth;
}
protected:
BinaryTreeNode<T>* _CreateTree(T* a, size_t size, size_t& index)
{
BinaryTreeNode<T>* root = NULL;
if (index < size && (a[index] != '#'))
{
root = new BinaryTreeNode<T>(a[index]);
root->_left = _CreateTree(a,size,++index);
root->_right = _CreateTree(a, size, ++index);
}
return root;
}
void _Destroy(BinaryTreeNode<T>* &root)
{
if (root == NULL)
return;
if (root->_left == NULL && root->_right == NULL)
{
delete root;
root = NULL;
return;
}
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
}
BinaryTreeNode<T>* _Copy(BinaryTreeNode<T>* root)
{
if (root == NULL)
return NULL;
BinaryTreeNode<T>* newRoot = new BinaryTreeNode<T>(root->_data);
newRoot->_left = _Copy(root->_left);
newRoot->_right = _Copy(root->_right);
return newRoot;
}
void _PrevOrder(BinaryTreeNode<T> *root)
{
if (root != NULL)
{
_PrevOrder(root->_left);
cout << root->_data << " ";
_PrevOrder(root->_right);
}
}
void _InOrder(BinaryTreeNode<T> *root)
{
if (root != NULL)
{
cout << root->_data << " ";
_InOrder(root->_left);
_InOrder(root->_right);
}
}
void _PostOrder(BinaryTreeNode<T>* root)
{
if (root != NULL)
{
_PostOrder(root->_left);
_PostOrder(root->_right);
cout << root->_data<<" ";
}
}
void _Size(BinaryTreeNode<T>* root, int& size)
{
if (root == NULL)
return;
else
++size;
_Size(root->_left,size);
_Size(root->_right,size);
}
int _Depth(BinaryTreeNode<T>* root)
{
int leftdepth = _Depth(root->_left);
int rightdepth = _Depth(root->_right);
return leftdepth > rightdepth ? leftdepth + 1 : rightdepth + 1;
}
private:
BinaryTreeNode<T>* _root;
};
void Test()
{
int a[10] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6 };
BinaryTree<int> b1(a, sizeof(a) / sizeof(a[0]));
BinaryTree<int> b2(b1);
/*int b[10] = { 1, 6, 3, '#', '#', 4, '#', '#', 5, 2};
BinaryTree<int> b3(b, sizeof(b) / sizeof(b[0]));
b3 = b2;*/
b2.PrevOrder();
b2.InOrder();
b2.PostOrder();
b2.LevelOrder();
int size = b2.Size();
cout << "size = " << size << endl;
int depth = b2.Depth();
cout << "depth = " << depth << endl;
}