1.节点的度:树中的一个节点拥有的子树称为该节点的度。一棵树的度是指该树中节点的最大度数,度为零的节点称为叶子或终端节点,度不为零的节点称为分支节点或非终端节点。除根节点之外的分支节点统称为内部节点。根节点又称为开始节点。
2.节点的层数从根算起:根的层数为1,也有很多书中将树根的层数定义为0。其余节点的层数等于其双亲节点的层数加1。双亲在同一层的节点互为堂兄弟。树中节点的最大层数称为树的高度或深度
3.若将树中每个节点的各子树看成是从左到右有次序的(即不能互换),则称该树为有序树;否则称为无序树。
4.树中只有根节点无前趋,它是开始节点;叶节点无后继,它们是终端节点。
5.二叉树中,每个节点最多只能有两棵子树,并且有左右之分。
6.二叉树具有以下重要的性质:二叉树第i层上的节点数目最多为 2i-1(i≥1)。2的i次方
深度为k的二叉树至多有 个2k-1节点(k≥1)。2的k次方
在任意一棵二叉树中,若终端节点的个数为 n0,度为2的节点数为n2 ,则n0 = n2+1。
7.满二叉树的特点:每一层上的节点数都达到最大值。
满二叉树中不存在度数为1的节点,每个分支节点均有两棵高度相同的子树,且树叶都在最下一层上。
8.完全二叉树:若一棵二叉树最多只有最下面的两层,其节点的度数可以小于2,并且最下一层上的节点都集中在该层最左边的若干位置上,则此二叉树称为完全二叉树。
9.完全二叉树的特点:满二叉树是完全二叉树,完全二叉树不一定是满二叉树。
在满二叉树的最下一层上,从最右边开始连续删去若干节点后得到的二叉树仍然是一棵完全二叉树。
在完全二叉树中,若某个节点没有左孩子,则它一定没有右孩子,即该节点必是叶节点。
10.二叉树的链式存储结构类型定义:一个树节点包含一个数据域和三个指针域,指针域被称为“左指针”和“右指针”还有父指针,它们分别指向节点的左右子树和父节点。
11.完全二叉树的顺序存储:数组第0个元素存放的是树中元素的个数。
12.数组实现的二叉树的优点:顺序存储结构既简单又节省存储空间。
13.数组实现的二叉树的缺点:在对顺序存储的完全二叉树做插入和删除节点操作时,要大量移动节点。而一般二叉树删除节点无需移动,若子树被删掉,则删除子树下所有节点。
14.二叉树的顺序存储:
#ifndef CTree_H_
#define CTree_H_
#pragma once
//--------完全二叉树的顺序存储--------
class CTree
{
protected:
char m_cArray[101];
int m_iCount;
public:
CTree();
~CTree();
bool isFull(){ if(m_iCount == 100) return true;return false;}
bool isEmpty(){if(m_iCount == 0)return true ; return false;}
void insert(char cData); //向完全二叉树插入数据
char remove(); //从完全二叉树移除数据
void show();
int getSize(){ return m_cArray[0];}
//--------完全二叉树特有的函数----------
//指定返回某个节点的父节点
char getParent(char _value);
//指定返回某个节点的左孩子
char getLeftChild(char _value);
//指定返回某个节点的右孩子
char getRightChild(char _value);
};
#endif
#include "Utility.h"
#include "Tree.h"
CTree::CTree()
{
memset(m_cArray,-1,101*sizeof(char));
m_iCount = 0;
m_cArray[0] = 0;
}
CTree::~CTree()
{
}
void CTree::insert(char cData)
{
if( isFull() )
{
cout<<"无法插入数据"<<endl;
return;
}
//可以插入数据
m_cArray[++m_iCount] = cData;
m_cArray[0]++;
}
char CTree::remove()
{
if(isEmpty())
{
cout<<"二叉树为空,无法移除元素"<<endl;
return ' ';
}
char cResult = m_cArray[m_iCount];
m_cArray[m_iCount--] = -1;
m_cArray[0]--;
return cResult;
}
void CTree::show()
{
for (int i = 1 ; i <= m_iCount ; ++i)
{
cout<<"m_cArray["<<i<<"] = "<<m_cArray[i]<<endl;
}
}
char CTree::getParent(char _value)
{
//寻找值为_value的节点的下标
int index = 0;
for( int i = 1 ; i <= m_iCount ; ++i )
{
if( _value == m_cArray[i] )
{
index = i;
//根据完全二叉树的特点获取其父节点下标
if(index == 1) //说明参数所描述的节点为根节点
return ' ';
//返回父节点的值
return m_cArray[index/2];
}
}
//二叉树中没有要寻找的节点
cout<<"没有找到值为:"<<_value<<" 的节点"<<endl;
return ' ';
}
char CTree::getLeftChild(char _value)
{
int index = 0;
for( int i = 1 ; i <= m_iCount ; ++i )
{
if( _value == m_cArray[i] )
{
index = i;
if(index > m_iCount/2 )
{
cout<<"该节点无孩子"<<endl;
return ' ';
}
return m_cArray[2*index];
}
}
return ' ';
}
char CTree::getRightChild(char _value)
{
int index = 0;
for( int i = 1 ; i <= m_iCount ; ++i )
{
if( _value == m_cArray[i] )
{
index = i;
if(index > m_iCount/2 )
{
cout<<"该节点无孩子"<<endl;
return ' ';
}
return m_cArray[2*index+1];
}
}
return ' ';
}
15.完全二叉树的链式存储:
#include "Utility.h"
//---------定义二叉树节点---------
typedef struct stNode
{
char cData;
int ID;
stNode * pParentNode;
stNode * pLeftChild;
stNode * pRightChild;
}NODE,*LPNODE;
LPNODE pRootNode = NULL; //二叉树根节点
int iCount = 0; //二叉树节点数量
//以完全二叉树形式插入节点
void insert(LPNODE & _pNode , char _data)
{
//--如果根节点为空--
if(_pNode == NULL)
{
//--先new该节点,并赋初始值--
LPNODE pInsertNode = new NODE;
iCount++;
pInsertNode->ID = iCount;
pInsertNode->cData = _data;
pInsertNode->pParentNode = NULL;
pInsertNode->pLeftChild = NULL;
pInsertNode->pRightChild = NULL;
_pNode = pInsertNode;
return;
}
//--如果根节点的左孩子为空--
if( _pNode->pLeftChild == NULL )
{
//--先new该节点,并赋初始值--
LPNODE pInsertNode = new NODE;
iCount++;
pInsertNode->ID = iCount;
pInsertNode->cData = _data;
pInsertNode->pParentNode = NULL;
pInsertNode->pLeftChild = NULL;
pInsertNode->pRightChild = NULL;
_pNode->pLeftChild = pInsertNode;
pInsertNode->pParentNode = _pNode;
return;
}
//--如果根节点的右孩子为空--
else if( _pNode->pRightChild == NULL )
{
//--先new该节点,并赋初始值--
LPNODE pInsertNode = new NODE;
iCount++;
pInsertNode->ID = iCount;
pInsertNode->cData = _data;
pInsertNode->pParentNode = NULL;
pInsertNode->pLeftChild = NULL;
pInsertNode->pRightChild = NULL;
_pNode->pRightChild = pInsertNode;
pInsertNode->pParentNode = _pNode;
return;
}
//---------寻找插入位置----------
int iLeftHeight = 0; //
int iRightHeight = 0; //
//判断某个节点的左子树的高度
LPNODE pTemp=_pNode->pLeftChild;
while(pTemp)
{
iLeftHeight++;
pTemp = pTemp->pRightChild;
}
//判断同一个节点的右子树的高度
pTemp=_pNode->pRightChild;
while(pTemp)
{
iRightHeight++;
pTemp=pTemp->pRightChild;
}
//如果两个子树高度不同,向右孩子插入数据
if( iLeftHeight != iRightHeight )
insert(_pNode->pRightChild,_data);
else
insert(_pNode->pLeftChild,_data);
}
//先序遍历二叉树
void Show_DLR(LPNODE _pNode)
{
if(_pNode)
{
cout<<_pNode->cData<<endl; //中
Show_DLR(_pNode->pLeftChild); //左
Show_DLR(_pNode->pRightChild); //右
}
}
//中序遍历二叉树
void Show_LDR(LPNODE _pNode)
{
if(_pNode)
{
Show_LDR(_pNode->pLeftChild); //左
cout<<_pNode->cData<<endl; //中
Show_LDR(_pNode->pRightChild); //右
}
}
//后序遍历二叉树
void Show_LRD(LPNODE _pNode)
{
if(_pNode)
{
Show_LRD(_pNode->pLeftChild); //左
Show_LRD(_pNode->pRightChild); //右
cout<<_pNode->cData<<endl; //中
}
}
//遍历二叉树寻找某个节点
LPNODE searchNode( LPNODE _pNode , char _data )
{
LPNODE pResult = NULL;
//如果传入节点为NULL,返回NULL
if(!_pNode)
return NULL;
//如果传入节点就是我们要寻找的节点,返回该节点指针
if(_pNode->cData == _data)
return _pNode;
else //传入节点不是我们要找的节点
{
if( pResult = searchNode(_pNode->pLeftChild,_data) )
return pResult;
else if( pResult = searchNode( _pNode->pRightChild,_data))
return pResult;
else
return NULL;
}
}
//显示找到节点的相关父、左孩子、右孩子信息
void show_SearchNode( LPNODE _pNode )
{
//----判定父节点----
if( _pNode->pParentNode )
cout<<"该节点父节点为:"<<_pNode->pParentNode->cData<<endl;
else
cout<<"该节点无父节点"<<endl;
//----判定左孩子----
if( _pNode->pLeftChild )
cout<<"该节点左孩子为:"<<_pNode->pLeftChild->cData<<endl;
else
cout<<"该节点无左孩子"<<endl;
//----判定右孩子----
if( _pNode->pRightChild )
cout<<"该节点左孩子为:"<<_pNode->pRightChild->cData<<endl;
else
cout<<"该节点无右孩子"<<endl;
}
//移除二叉树中最后一个节点
LPNODE remove( LPNODE _pNode )
{
LPNODE pRemove = NULL;
//如果传入节点为NULL,返回NULL
if(!_pNode)
return NULL;
//如果传入节点就是我们要寻找的节点,返回该节点指针
if( _pNode->ID == iCount )
return _pNode;
else //传入节点不是我们要找的节点
{
if( pRemove = remove(_pNode->pLeftChild) )
return pRemove;
else if( pRemove = remove( _pNode->pRightChild))
return pRemove;
else
return NULL;
}
}
void clearTree()
{
//-------删除整个二叉树--------
while(iCount)
{
LPNODE pRemove = remove(pRootNode);
if(iCount == 1) //pRemove为根节点
{
Safe_Delete(pRootNode);
iCount--;
}
else
{
LPNODE pParent = pRemove->pParentNode;//保存待删除节点父节点指针
pRemove->pParentNode = NULL;
if(pParent->pLeftChild == pRemove)
pParent->pLeftChild = NULL;
if(pParent->pRightChild == pRemove)
pParent->pRightChild = NULL;
Safe_Delete(pRemove);
iCount--;
}
}
}
void main()
{
//字符数组
char cArray[26] = {'A','B','C','D','E','F','G'
,'H','I','J','K','L','M','N',
'O','P','Q','R','S','T','U',
'V','W','X','Y','Z'};
for(int i = 0 ; i < 26 ; ++i)
insert(pRootNode,cArray[i]);
cout<<"-----先序遍历-----"<<endl;
Show_DLR(pRootNode);
cout<<"-----中序遍历-----"<<endl;
Show_LDR(pRootNode);
cout<<"-----后序遍历-----"<<endl;
Show_LRD(pRootNode);
char cSearch = 'Z';
LPNODE pSearchNode = searchNode(pRootNode,cSearch);
if(pSearchNode)
{
cout<<"找到节点:"<<cSearch<<endl;
show_SearchNode(pSearchNode);
}
else
cout<<"没有找到"<<cSearch<<"节点"<<endl;
//----寻找待删除的节点----
LPNODE pRemove = remove(pRootNode);
if( pRemove )//寻找到了待删除的节点
{
LPNODE pParent = pRemove->pParentNode;//保存待删除节点父节点指针
if(pParent->pLeftChild == pRemove)
pParent->pLeftChild = NULL;
if(pParent->pRightChild == pRemove)
pParent->pRightChild = NULL;
Safe_Delete(pRemove);
iCount--;
}
else
cout<<"二叉树为空"<<endl;
//------清除整个二叉树------
clearTree();
//------重新插入数据--------
for(int i = 0 ; i < 26 ; ++i)
insert(pRootNode,cArray[i]);
system("pause");
}