满二叉树
所有节点的度要么为0,要么为2,且所有的叶子节点都在最后一层。
1、第i层的节点数量为:2^{i-1}
2、总节点数n = 2^h-1,h为高度
这里说的满二叉树其实就是其他地方说的完美二叉树。
完全二叉树
叶子节点只会出现在最后2层,且最后一层的叶子节点都靠左对齐。
相当于是一个数组,其从上到下,从左到右排列。
1、根节点编号为N,则左孩子编号为2N+1,右孩子为2N+2
2、如果完全二叉树的左孩子编号为M,则根节点的编号为(M-1)/2
3、如果完全二叉树的右孩子编号为M,则根节点编号为(M-2)/2
4、如果完全二叉树孩子编号为M,则根节点的编号为(M-1)/2
//CompleteBinaryTree.h
#pragma once
/*
满二叉树
所有节点的度要么为0,要么为2,且所有的叶子节点都在最后一层。
1、第i层的节点数量为:2^{i-1}
2、总节点数n = 2^h-1,h为高度
完全二叉树
叶子节点只会出现在最后2层,且最后一层的叶子节点都靠左对齐。
相当于是一个数组,其从上到下,从左到右排列。
1、根节点编号为N,则左孩子编号为2N+1,右孩子为2N+2
2、如果完全二叉树的左孩子编号为M,则根节点的编号为(M-1)/2
3、如果完全二叉树的右孩子编号为M,则根节点编号为(M-2)/2
4、如果完全二叉树孩子编号为M,则根节点的编号为(M-1)/2
*/
#include <iostream>
template <class T>
class CompleteBinaryTree
{
public:
CompleteBinaryTree()
{
m_num = 0;
pRoot = nullptr;
}
~CompleteBinaryTree()
{
if (pRoot)
{
delete pRoot;
pRoot = nullptr;
}
}
void insertNode(const T&data);//插入
void preTravel();//先序遍历,可转换成遍历数组,只是按照先序遍历的顺序来遍历数组中的索引值即可
void preTravelIndex(int data);
int addr2index(const T *node);//返回node节点对应的数组索引值
T *getParent(const T *node);//已知某个节点地址返回其父节点地址
T *getLeftChild(const T *node);//已知某个节点地址返回其右孩子地址
T *getRightChild(const T *node);//已知某个节点地址返回其左孩子地址
T *getNodeAdd(const T &data);//已知节点数据,返回节点地址
bool deleteNode(const T &node);//删除节点
private:
T *pRoot; //根节点地址
size_t m_num; //节点数量
};
template <class T>
void CompleteBinaryTree<T>::insertNode(const T& data)
{
//新开内存
T *pNew = new T[m_num + 1];
if (pRoot)
{
memcpy(pNew, pRoot, sizeof(T)*m_num);
delete pRoot;
}
pRoot = pNew;
pRoot[m_num++] = data;
}
template <class T>
void CompleteBinaryTree<T>::preTravel()
{
int iRootIdx = addr2index(pRoot);
preTravelIndex(iRootIdx);
}
template <class T>
void CompleteBinaryTree<T>::preTravelIndex(int data)
{
if (data <0 || data >= m_num)
return;
std::cout << pRoot[data]<<" ";
int iLeft = 2 * data + 1;
int iRight = 2 * data + 2;
preTravelIndex(iLeft);
preTravelIndex(iRight);
}
template <class T>
int CompleteBinaryTree<T>::addr2index(const T* node)
{
int index = 0;
T *pTempNode = pRoot;
while (index < m_num)
{
if (pTempNode == node)
return index;
index++;
pTempNode++;
}
return index;
}
template<class T>
T * CompleteBinaryTree<T>::getParent(const T * node)
{
int idx = addr2index(node);
if (-1 == idx)
return nullptr;
if (idx < 1)
return nullptr;
return pRoot + (idx-1)/2;
}
template<class T>
inline T * CompleteBinaryTree<T>::getLeftChild(const T * node)
{
int idx = addr2index(node);
if (-1 == idx)
return nullptr;
return pRoot + (2*idx+1);
}
template<class T>
inline T * CompleteBinaryTree<T>::getRightChild(const T * node)
{
int idx = addr2index(node);
if (-1 == idx)
return nullptr;
return pRoot + 2 * idx + 2;
}
template<class T>
T * CompleteBinaryTree<T>::getNodeAdd(const T & data)
{
for (size_t i = 0; i < m_num; i++)
{
if (data == pRoot[i])
return pRoot + i;
}
return nullptr;
}
template<class T>
bool CompleteBinaryTree<T>::deleteNode(const T & node)
{
//节点是否在树中
int index = addr2index(getNodeAdd(node));
if (-1 == index)
return false;
#if 0
//思路1
//删除的内存没释放
//循环从要删除的节点的下一个节点往前挪动
for (int i = index + 1; i < m_num; i++)
pRoot[i - 1] = pRoot[i];
m_num--;
#else
//1。如果树中只有一个元素,直接释放内存
if (1 == m_num)
{
delete[]pRoot;
pRoot = nullptr;
m_num = 0;
return true;
}
T *pTem = new T[m_num - 1];
if(index != 1)//是第一个节点,则不需要拷贝
memcpy(pTem, pRoot, index * sizeof(T));
if(index < m_num-1)
memcpy(pTem + index, pRoot + index+1, (m_num - 1 - index) * sizeof(T));
delete[]pRoot;
pRoot = pTem;
m_num--;
return true;
#endif
}
#include "CompleteBinaryTree.h"
int main()
{
CompleteBinaryTree<char> tree;
for (int i = 0; i < 10; i++)
tree.insertNode('A'+i);
tree.preTravel();
std::cout << "\n";
char *p = tree.getLeftChild(tree.getNodeAdd('B'));
std::cout << *p << std::endl;
bool bIsOK = tree.deleteNode('C');
if (bIsOK)
std::cout << "OK" << std::endl;
else
std::cout << "NG" << std::endl;
tree.preTravel();
return 0;
}