Binary Trees
Introduction
Full Binary Tree
Each node being either
- Leaf
- Internal node with exactly two non-empty children (有孩子必须有两个孩子)
Complete Binary Tree
- If the height of the tree is
d
, then all levels except possibly leveld-1
are
completely full - The bottom level has all nodes filled in from the left side
(除了最后一层都是满的,最后一层是从左到右排)
Full Binary Tree Theorem
- The number of leaves in a non-empty full binary tree is one more than the number of internal nodes. 叶子数=内部节点+1
- The number of null pointers in a non-empty binary tree is one more than the number of nodes in the tree.空指针数=总节点+1
Node ADT
Template <class Elem> class BinNode {
public:
virtual Elem& val( ) =0;
virtual BinNode* left( ) const = 0;
virtual BinNode* right( ) const = 0;
virtual void setVal( const Elem& ) = 0;
virtual void setLeft( BinNode* ) = 0;
virtual void setRight( BinNode* ) = 0;
virtual bool isLeaf( ) = 0;
}
// Binary tree node class
template <class Elem>
class BinNodePtr : public BinNode<Elem> {
private:
Elem it; // The node's value
BinNodePtr* lc; // Pointer to left child
BinNodePtr* rc; // Pointer to right child
public:
BinNodePtr() { lc = rc = NULL; }
BinNodePtr(Elem e, BinNodePtr* l=NULL, BinNodePtr* r=NULL)
{ it = e; lc = l; rc = r; }
Elem& val() { return it; }
void setVal(const Elem& e) { it = e; }
inline BinNode<Elem>* left() const
{ return lc; }
void setLeft(BinNode<Elem>* b)
{ lc = (BinNodePtr*)b; }
inline BinNode<Elem>* right() const
{ return rc; }
void setRight(BinNode<Elem>* b)
{ rc = (BinNodePtr*)b; }
bool isLeaf()
{ return (lc == NULL) && (rc == NULL); }
};
Traversal
Preorder Traversal
- Visit each node before visiting its children.
- ABCDEFGHIJ
template <class Elem>
void preorder(BinNode<Elem>* subroot) {
if (subroot == NULL) return; // Empty
visit(subroot); // Perform some actions
preorder(subroot->left()); // left
preorder(subroot->right()); // right
}
Postorder traversal
- Visit each node after visiting its children.
- CBFGEJIHA
template <class Elem>
void postorder(BinNode<Elem>* subroot) {
if (subroot == NULL) return; // Empty
postorder(subroot->left()); // left
postorder(subroot->right()); // right
visit(subroot); // Perform some actions
}
Inorder traversal
- Visit the left subtree, then the node, then the right subtree.
- CBAFEGDIH
template <class Elem>
void inorder(BinNode<Elem>* subroot) {
if (subroot == NULL) return; // Empty
inorder(subroot->left()); // left
visit(subroot); // Perform some actions
inorder(subroot->right()); // right
}
Examples
Write a recursive function that returns the height of a binary tree
template <class Elem> int findHeight(BinNode<Elem>* subroot){ if (subroot == NULL) return 0; // Empty subtree return 1 + max(height(subroot->left()), height(subroot->right())); }
Write a recursive function that search value
K
in a binary tree. The function returns true if valueK
is existtemplate <class Key, class Elem, class KEComp> bool search(BinNode<Elem>* subroot, Key K){...} if (subroot == NULL) return false; if (subroot->value() == K) return true; elseif (search(subroot->left())) return true; else return search(subroot->right()); }
Binary Search Trees
Introduction
- All elements stored in the left subtree of a node with value
K
havevalues < K
- All elements stored in the right subtree of a node with value
K
havevalues >= K
ADT
// BST implementation for the Dictionary ADT
template <class Key, class Elem, class KEComp, class EEComp>
class BST : public Dictionary<Key, Elem,KEComp, EEComp> {
private:
BinNode<Elem>* root; // Root of the BST
int nodecount; // Number of nodes
void clearhelp(BinNode<Elem>*);
BinNode<Elem>* inserthelp(BinNode<Elem>*, const Elem&);
BinNode<Elem>* deletemin(BinNode<Elem>*,BinNode<Elem>*&);
BinNode<Elem>* removehelp(BinNode<Elem>*,const Key&,BinNode<Elem>*&);
bool findhelp(BinNode<Elem>*, const Key&,Elem&) const;
void printhelp(BinNode<Elem>*, int) const;
public:
BST() { root = NULL; nodecount = 0; }
~BST() { clearhelp(root); }
void clear() { clearhelp(root); root = NULL; nodecount = 0;}
}
INSERTHELP
template <class Key, class Elem, class KEComp, class EEComp>
BinNode<Elem>* BST<Key,Elem,KEComp,EEComp>::inserthelp( BinNode<Elem>* subroot, const Elem& val ) {
if (subroot == NULL) // Empty: create node
return new BinNodePtr<Elem>(val,NULL,NULL);
if (EEComp::lt(val, subroot->val()))
subroot->setLeft(inserthelp(subroot->left(), val));
else
subroot->setRight(inserthelp(subroot->right(), val));
return subroot; // Return subtree with node inserted
}
根据搜索树特性寻找,在空指针处插值。
注意这里是把值一层一层返回给上级。
DELETEMIN
template <class Key, class Elem, class KEComp, class EEComp>
BinNode<Elem>* BST<Key, Elem, KEComp, EEComp>::deletemin(BinNode<Elem>* subroot, BinNode<Elem>*& min) {
if (subroot->left() == NULL) {
min = subroot;
return subroot->right();
}
else { // Continue left
subroot->setLeft(
deletemin(subroot->left(), min));
return subroot;
}
}
找到最小值就让min
指向它,并没有真正的删除。
用最小值节点的右子树(排序下来之比最小值节点大一个)的节点代替最小值节点的位置。
REMOVEHELP
template <class Key, class Elem, class KEComp, class EEComp>
BinNode<Elem>* BST<Key,Elem,KEComp,EEComp>::removehelp(BinNode<Elem>* subroot, const Key& K, BinNode<Elem>*& t) {
//查找部分
if (subroot == NULL) return NULL;
else if (KEComp::lt(K, subroot->val()))
subroot->setLeft(removehelp(subroot->left(), K, t));
else if (KEComp::gt(K, subroot->val()))
subroot->setRight(removehelp(subroot->right(), K, t));
//以下是找到了k值点
else { // Found it: remove it
BinNode<Elem>* temp;
t = subroot;
//无左子树,直接把右子树接上
if (subroot->left() == NULL)
subroot = subroot->right();
//无右子树,直接把左子树接上
else if (subroot->right() == NULL)
subroot = subroot->left();
//两个子树都有,选择右子树的最小节点来和父节点交换。
else { // Both children are non-empty
subroot->setRight(deletemin(subroot->right(), temp));
//此处temp接受了右子树最小值的返回值
//交换操作
Elem te = subroot->val();
subroot->setVal(temp->val());
temp->setVal(te);
//t用来返回被删除节点的值
t = temp;
}
}
return subroot;
}
- 先进行常规的搜索操作
- 找到待删除节点
- 无左子树,直接用右子树替换
- 无右子树,直接用左子树替换
- 都有,选择右子树的最小节点来和该节点交换
(如果选左子树最大节点可能会在替换时发生问题(注意右子树是大于+等于))
CLEARHELP
template <class Key, class Elem, class KEComp, class EEComp>
void BST<Key,Elem,KEComp,EEComp>::clearhelp(BinNode<Elem>* subroot) {
if (subroot == NULL) return;
clearhelp(subroot->left());
clearhelp(subroot->right());
delete subroot;
}
其实就是postorder遍历+删除。
PRINTHELP
template <class Key, class Elem, class KEComp, class EEComp>
void BST<Key,Elem,KEComp,EEComp>::printhelp(BinNode<Elem>* subroot, int level) {
if (subroot == NULL) return NULL;
printhelp(subroot->left(), level+1);
for (int i=0; i<level; i++) cout << “ “;
cout << subroot->val() << “\n”;
printhelp(subroot->right(), level+1);
}
INSERT
bool insert(const Elem& e) {
root = inserthelp(root, e);
nodecount++;
return true;
}
REMOVE
bool remove(const Key& K, Elem& e) {
BinNode<Elem>* t = NULL;
root = removehelp(root, K, t);
if (t == NULL) return false;
e = t->val();
nodecount--;
delete t;
return true;
}
Priority Queues and Heaps
Array-Based Complete BT
- P a r e n t ( r ) = ⌊ ( r − 1 ) / 2 ⌋ i f r ≠ 0 a n d r < n Parent (r) = \lfloor (r - 1) / 2\rfloor\ \ if \ \ r ≠ 0\ \ and\ \ r < n Parent(r)=⌊(r−1)/2⌋ if r=0 and r<n
- L e f t c h i l d ( r ) = 2 r + 1 i f 2 r + 1 < n Leftchild(r) = 2r + 1\ \ if \ \ 2r+1 < n Leftchild(r)=2r+1 if 2r+1<n
- R i g h t c h i l d ( r ) = 2 r + 2 i f 2 r + 2 < n Rightchild(r) = 2r + 2\ \ if\ \ 2r +2 < n Rightchild(r)=2r+2 if 2r+2<n
- L e f t s i b l i n g ( r ) = r − 1 i f r i s e v e n , r > 0 a n d r < n Leftsibling(r) = r - 1\ \ if\ \ r\ \ is\ \ even,\ r > 0 \ \ and\ \ r < n Leftsibling(r)=r−1 if r is even, r>0 and r<n
-
R
i
g
h
t
s
i
b
l
i
n
g
(
r
)
=
r
+
1
i
f
r
i
s
o
d
d
,
r
+
1
<
n
Rightsibling(r) = r + 1\ \ if \ \ r\ \ is\ \ odd, \ r +1 < n
Rightsibling(r)=r+1 if r is odd, r+1<n
Heaps
Properties
- Complete Binary Tree
- Value stored in a heap are partially ordered
Types
-
Min-heap: All values less than or equal to child values
- Max-heap: All values greater than or equal to childvalues
- Max-heap: All values greater than or equal to childvalues
ADT
template<class Elem,class Comp> class maxheap{
private:
Elem* Heap; // Pointer to the heap array
int size; // Maximum size of the heap
int n; // Number of elems now in heap
void siftdown(int); // Put element in place
public:
maxheap(Elem* h, int num, int max);
int heapsize() const;
bool isLeaf(int pos) const;
int leftchild(int pos) const;
int rightchild(int pos) const;
int parent(int pos) const;
bool insert(const Elem&);
bool removemax(Elem&);
bool remove(int, Elem&);
void buildHeap();
};
Buildheap Function
public void buildheap() // Heapify contents
{
for (int i=n/2-1; i>=0; i--) //逐个更新,对于leaf不用叫shiftdown
siftdown(i); //注意这里是从下往上换的
}
template <class Elem, class Comp>
void maxheap<Elem,Comp>::siftdown(int pos) {
while (!isLeaf(pos)) { //没必要更新leaf(这里都只是父节点和子节点比较,leaf无子节点)
int j = leftchild(pos); //用j,rc 获取左右节点的值
int rc = rightchild(pos);
if ((rc<n) && Comp::lt(Heap[j],Heap[rc])) //保证rc不为空(n是个数)
j = rc; //j永远指向两个子结点中大的那个
if (!Comp::lt(Heap[pos], Heap[j])) //如果当前节点比最大子节点大 结束
return;//用于没有交换操作,不用管下面的节点
swap(Heap, pos, j); //如果小于,交换两个的值(不交换指针位置)
pos = j;//沿着被交换的节点继续向下递归
}
}
** Removemax Function**
template <class Elem, class Comp>
bool maxheap<Elem, Comp>:: removemax(Elem& it) {
if (n == 0) return false; // Heap is empty
swap(Heap, 0, --n); // Swap max with end
if (n != 0) siftdown(0);//防止仅有一个节点
it = Heap[n]; // Return max value
return true;
}
Remove Function
template <class Elem, class Comp>
bool maxheap<Elem, Comp>::remove(int pos, Elem& it) {
bool flag = false;//用来表示替换节点的大小,大于父节点是true,小于是false
if ((pos < 0) || (pos >= n)) return false;//防止pos位置为空
//交换删除节点和最后一个节点的值
swap(Heap, pos, --n);//先减再交换(从0标号)
//如果当前位置比父节点大
while ((pos != 0) && (Comp::gt(Heap[pos],Heap[parent(pos)]))){
swap(Heap, pos, parent(pos));//交换当前节点和父节点的值
pos = parent(pos);//pos始终指着比较大的一个
flag=true;
}
//如果大于父节点,一定大于父节点的子节点
//此处是对于没有大于父节点的向下替换操作
if (!flag) siftdown(pos);
it = Heap[n];//用于返回被删除的值
return true;
}
Insert Function
template <class Elem, class Comp> // Insert element
bool maxheap<Elem, Comp>::insert(const Elem& val) {
if (n >= size) return false; // Heap is full
int curr = n++;
Heap[curr] = val; // Start at end of heap
// Now sift up until curr's parent > curr
while ((curr!=0) && (Comp::gt(Heap[curr], Heap[parent(curr)]))){
swap(Heap, curr, parent(curr));
curr = parent(curr);
}
return true;
}
Creat a Heap
- Buildheap Function : Θ ( l o g n ) \Theta(log\ n) Θ(log n)
- Insert n values to a heap using insert function : Θ ( n ) \Theta(n) Θ(n)
Priority Queues
- Linked List
- Insert appends to a linked list ( O ( 1 ) O(1) O(1) )
- Remove max value determines the maximum by scanning the list ( O ( n ) O(n) O(n) )
- Sorted Linked List (decreasing order)
- Insert places an element in its correct position ( O ( n ) O(n) O(n) )
- Remove max value simply removes the head of the list ( O ( 1 ) O(1) O(1) )
- Heap
- Both insert and remove max value are O ( l o g n ) O( log n ) O(logn) operations
Huffman Coding Trees
- Combine the two smallest values each time
- Prefix Property : No code in the set is the prefix of another
- E x p e c t e d C o s t p e r l e t t e r = ∑ f r e q u e n c y × b i t ∑ f r e q u e n c y Expected\ Cost\ per\ letter=\frac{\sum frequency × bit }{\sum frequency} Expected Cost per letter=∑frequency∑frequency×bit
ADT
template <class Elem>
class HuffNode { // Node abstract base class
public:
virtual int weight() = 0;
virtual bool isLeaf() = 0;
virtual HuffNode* left() const = 0;
virtual void setLeft(HuffNode*) = 0;
virtual HuffNode* right() const = 0;
virtual void setRight(HuffNode*) = 0;
};
FreqPair
template <class Elem>
class FreqPair { // An element/frequency pair
private:
Elem it; // An element of some sort
int freq; // Frequency for the element
public:
FreqPair(const Elem& e, int f) // Constructor
{ it = e; freq = f; }
~FreqPair() { } // Destructor
int weight() { return freq; } // Return the weight
Elem& val() { return it; } // Return the element
};
**Leaf Node**
```cpp
template <class Elem> // leaf node subclass
class LeafNode: public HuffNode<Elem> {
private:
Freqpair<Elem>* it; // Frequency pair
public:
LeafNode(const Elem& val, int freq) //constructor
{ it = new Freqpair<Elem>(val,freq); }
int weight() { return it->weight(); } //Return frequency
Freqpair<Elem>* val() { return it; }
bool isLeaf() { return true; }
virtual HuffNode* left() const { return NULL; }
virtual void setLeft(HuffNode*) { }
virtual HuffNode* right() const { return NULL; }
virtual void setRight(HuffNode*) { }
};
Internal Node
template <class Elem> //Internal node subclass
class IntlNode: public HuffNode<Elem> {
private:
HuffNode<Elem>* lc; //left child
HuffNode<Elem>* rc; //right child
int wgt; //Subtree weight
public:
IntlNode(HuffNode<Elem> * l; HuffNode<Elem> * r)
{ wgt = l->weight() + r->weight(); lc = l; rc = r; }
int weight() { return wgt; } // Return frequency
bool isLeaf() { return false; }
HuffNode<Elem>* left() const { return lc; }
void setLeft(HuffNode<Elem>* b) { lc = (HuffNode*)b; }
HuffNode<Elem>* right() const { return rc; }
void setRight(HuffNode<Elem>* b) { rc = (HuffNode*)b; }
};
Huffman Tree
template <class Elem>
class HuffTree {
private:
HuffNode<Elem>* theRoot;
public:
HuffTree(Elem& val, int freq)
{ theRoot = new LeafNode<Elem>(val,freq);}
HuffTree(HuffTree<Elem>* l, HuffTree<Elem>* r)
{ theRoot = new IntlNode<Elem>(l->root(), r->root());}
~HuffTree() {}
HuffNode<Elem>* root() { return theRoot; }
int weight() { return theRoot->weight(); }
};
Huffman Compare
template <class Elem> class HHCompare {
public:
static bool lt(HuffTree<Elem>* x, HuffTree<Elem>* y)
{ return x->weight() < y->weight(); }
static bool eq(HuffTree<Elem>* x, HuffTree<Elem>* y)
{ return x->weight() = = y->weight(); }
static bool gt(HuffTree<Elem>* x, HuffTree<Elem>* y)
{ return x->weight() > y->weight(); }
};
Build Huffman Tree
template <class Elem> HuffTree<Elem>*
//SLL->Sorted Linked List
buildHuff(SLList<HuffTree<Elem>*,HHCompare<Elem>>* f1){
//估计setStart()是把f1放到合适的位置
HuffTree<Elem>* temp1, *temp2, *temp3;
for (f1->setStart();
f1->leftLength() + f1->rightLength()>1;
f1->setStart()) { //While at least two items left
f1->remove(temp1); // Pull first two trees off the list
f1->remove(temp2);
temp3 = new HuffTree<Elem>(temp1, temp2);
f1->insert(temp3); // Put the new tree back on list
delete temp1; // Delete the remnants
delete temp2;
}
return temp3;
}