演算法導論第十三章

2021-06-15 21:30:56 字數 2974 閱讀 5898

紅黑樹是一種較為平衡的搜尋樹, 當然滿足所有搜尋樹應該具有的特點.

紅黑樹的幾個性質:

1. 節點或紅或黑 2. 根是黑的 3. 葉是黑的(葉均為nil, 是所謂的外節點, 而有值的節點均為內節點)

4. 如果乙個節點是紅的,則它的子女均為黑的 5. 對於任何節點, 從該節點到該節點的子孫葉節點的所有路徑上所包含的黑節點數量相同。

從定義可以得到定理:一顆n個內節點的紅黑樹高度最多2lg(n+1).

乙個完全2叉樹的高度是lg(n+1), 所以可見紅黑樹的平衡性是相當不錯的。

紅黑樹和普通的搜尋樹相比,主要的區別在於,紅黑樹進行插入刪除之後,很可能會導致樹破壞了上述5個性質,因而需要作一些調整: 為了做調整,有兩個基礎操作,分別是針對乙個節點進行左旋或者右旋操作, 這兩個操作都不會影響樹本身的性質。

下面是我自己寫的一些code. 都是根據書中思路所寫,書中用陣列來表示樹, 我用節點來表示,有一些差別。 leftrotate, rightrotate.  除去insert和delete之外,紅黑樹和搜尋樹的行為均相同, 其中m_null表示空節點,屬於黑節點。

template

class treenode

treenode(const ty& __x, treenode* leftchild, treenode* rightchild, treenode* parent)

: m_parent(parent), m_left(leftchild), m_right(rightchild), m_value(__x), m_black(false) {}

treenode(const ty& __x) : m_parent(0), m_left(0), m_right(0), m_black(false) {}

bool m_black;

ty m_value;

treenode* m_parent;

treenode* m_left;

treenode* m_right;

treenode* left()

treenode* right()

treenode* parent()

ty& value()

static treenode* makenode(const ty& __x, treenode* leftchild = 0, treenode* rightchild = 0, treenode* parent = 0)

bool isred() const

bool isblack() const

void setred()

void setblack()

};typedef treenodenode_type;

void leftrotate(node_type* node)

else

else}}

void rightrotate(node_type* node)

else

else}}

插入和搜尋樹插入相仿,只是加入了一些影響紅黑的校正部分:

void insert(const value_type& __x)

while(curnode != m_null)

else

}else

else}}

node->setred();

insertfixup(node);

}void insertfixup(node_type* node)

else // 叔叔的顏色是黑

parent = node->parent();

rightrotate(grandparent);

grandparent->setred();

node->parent()->setblack();}}

else

else // 叔叔的顏色是黑

leftrotate(grandparent);

grandparent->setred();

node->parent()->setblack();}}

}m_root->setblack();

}刪除:

void erase(const value_type& __x)

if (node->left() == m_null || node->right() == m_null)

else

node_type** parent;

if (node->parent() == m_null)

else

else

}node_type* fixpara;

if (node->left() != m_null)

else

if (node->isblack())

m_null->m_parent = 0;

delete node; 

void erasefixup(node_type* node)

if (sibling->left()->isblack() && sibling->right()->isblack())

else

sibling->m_black = parent->m_black;

parent->setblack();

sibling->right()->setblack();

leftrotate(parent);

node = m_root;}}

else // node是右子女

if (sibling->right()->isblack() && sibling->left()->isblack())

else

sibling->m_black = parent->m_black;

parent->setblack();

sibling->left()->setblack();

rightrotate(parent);

node = m_root;}}

}node->setblack();

}

第十三章 併發

13.1 動機 13.2 基本執行緒 如果必須要控制現成的執行順序,最好是根本不用執行緒,而是自己編寫特定順序彼此控制的協作子程式。繼承thread類或者實現runnable介面。內部類實現。13.3 共享受限資源 1 如果要對類中的某個方法進行同步控制,最好同步所有方法。如果忽略了其中乙個,通常很...

第十三章 類

1.類簡單地說是乙個性的資料型別。類當中有資料成員,和成員函式。類的基本思想就是體現出資料的抽象和封裝。2.這裡只需要說明乙個問題即可 就是類成員函式的const型別 class screen public const int get const int i const int j const 這裡...

第十三章 事件

1 事件的作用 事件是對委託的封裝,如同屬性對字段的封裝。封裝後可以在委託上實現更複雜的邏輯。1.1 封裝訂閱 委託允許使用 對其進行賦值,但向乙個委託例項賦值多個委託時,使用 會造成覆蓋之前的委託。事件只支援 或 對事件進行賦值 1.2 封裝發布 委託可以在其他類進行訪問,而事件可以確保只有包容類...