本文简单简介二叉树的概念,并给出平衡一颗二叉树的方法
关于二叉树
现在有N个元素的数组或者链表,要查找一个元素必须遍历数组直到找到元素。假如元素在是数组中最后一个或者数组中不存在这样的元素,那么很不幸,我们要遍历整个数组。如果N非常大,那将是非常痛苦的一件事情。
用二叉树情况就好多了:
1. 更快的查找
2. 增加元素时,元素被自动排列
原理:
在链表或数组中,元素一个接着一个,如图
在二叉树中情况不太一样了
每个元素连着两个元素,左孩子和右孩子。他们存储的值的关系有如下规定
Value(left)<Value(middle)<=Value(right)
排序:
在二叉树中利用递归你能很方便的排序
前序遍历
PrintElement(pTopMostElement)
.
.
void PrintElement(TreeElement* pElement)
{
if (pElement)
{
PrintElement(pElement->LeftChild)
pElement->PrintMe()
PrintElement(pElement->RightChild)
}
}
后序遍历:
PrintElementReversed(pTopMostElement)
.
.
void PrintElementReversed(TreeElement* pElement)
{
if (pElement)
{
PrintElementReversed(pElement->RightChild)
pElement->PrintMe()
PrintElementReversed(pElement->LeftChild)
}
}
如何使二叉树平衡?
添加元素的顺序将影响二叉树的形态,以3,6,4,8,1,9,2,7,5的顺序得到
以1,2,3,4,5,6,7,8,9将得到
有以下方法可以考虑:
1. 以非排序的元素插入元素,不能要求给出的元素是高度不排序的
2. 以一组随机元素构造二叉树,然后替换这些元素,然后通过旋转得到平衡的树。参考随机树。
3. 重构这稞树
重构整稞树
1. 把元素拷贝到数组中,以升序排序
2. 清空这棵树
3. 从数组中高度不排序的选取元素插入树中可以这样完成第三步:
可以递归的实现:
// Assuming array ranges from [0..arraySize-1]
GetFromOrderedArray(0,arraySize-1)
.
.
void GetFromOrderedArray(int lowBound,int highBound)
{
if (hi < low) return;
middlePos = lowBound+(highBound-lowBound)/2
// middlePos is now at the element in the middle
// between lowBound and highBound, so we just add
// it to the tree
AddElement ( theOrderedArray[middlePos] )
// Pick the middle one "to the left"
AddFromOrderedArray(lowBound,middlePos-1)
// Pick the middle one "to the right"
AddFromOrderedArray(middlePos+1,highBound)
}
删除一个元素
首先要找到要删除的元素E,有两种方法:
1. 通过遍历找到这个元素E
2. 给每个元素一个指向双亲的指针
接下来就是删除的过程了:
1. 剪断E与他双亲的连接
2. 将左右孩子所在的子树同其他元素一样加到树中
3. 删除E
void RemoveElement(TreeElement* theOneToRemove)
{
TreeElement* pParent = theOneToRemove->GetParent();
// Ok, so it has a parent, then we'll simply just disconnect it.
if (pParent)
{
if (pParent->GetLeftChild() == theOneToRemove)
{
pParent->SetLeftChild(NULL);
}
else
{
ASSERT(pParent->GetRightChild() == theOneToRemove);
pParent->SetRightChild(NULL);
}
}
else
{
// No parent? Then we're removing the root element.
theTopMostElement = NULL;
}
// Disconnected, now we reconnect its children (if any)
// just by adding them as we add any other node.
if (theOneToRemove->GetLeftChild())
AddElement(theOneToRemove->GetLeftChild());
if (theOneToRemove->GetRightChild())
AddElement(theOneToRemove->GetRightChild());
//Zap the element (if that's what you want to do)
delete theOneToRemove;
}
注解:
通过函数回调 遍历二叉树
注:函数回调例如AddElement(theOneToRemove->GetRightChild());
简而言之,回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。
可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定原型、某些限制条件(如返回值为int)的被调用函数。
#内容选自CodeGuru
若理解错误,欢迎指正!