げんさがせひろじゅ

本页使用了标题或全文手工转换
维基百科ひゃっか自由じゆうてき百科ひゃっかぜん
Binary search tree
类型
发明时间1960ねん
发明しゃP·F·ぬる德利とっくり安德あんとく鲁·から纳德·ぬのおもえ安德あんとく鲁·りんたく斯·N·まれともえいさお
ようだいO符号ふごう表示ひょうじてき时间复杂
算法さんぽう 平均へいきん さい
そら
搜索そうさく
插入そうにゅう
删除
3层二叉查找树

二叉查找树英語えいごBinary Search Tree),也称为また搜索そうさくゆうじょまたordered binary treeあるはいじょまたsorted binary tree),ゆび一棵空树或者具有下列性质的また

  1. わか任意にんい节点てきひだり树不そら,则左树上所有しょゆう节点てき值均しょう于它てき节点てき值;
  2. わか任意にんい节点てき右子ゆうこ树不そら,则右树上所有しょゆう节点てき值均だい于它てき节点てき值;
  3. 任意にんい节点てきひだり右子ゆうこ树也ぶん别为二叉查找树;

二叉查找树相比于其他数据结构的优势在于查找、插入そうにゅうてき时间复杂较低。为。二叉查找树是基础性数据结构,よう于构けんさら抽象ちゅうしょうてきすうすえ结构,如集合しゅうごう多重たじゅうしゅう关联すうひとし

二叉查找树的查找过程和また类似,通常つうじょうさいまた链表さく为二叉查找树的そん储结构ちゅうじょへん历二叉查找树可得到一个关键字的有序序列,いち个无じょ序列じょれつ透過とうかけん構一棵二叉查找树变成一个有序序列,けん構树てき过程そく为对无序序列じょれつ进行查找てき过程。每次まいじ插入そうにゅうてきしんてき结点二叉查找树上新的叶子结点,ざい进行插入そうにゅう操作そうさ时,必移动其它结てんただ需改动某个结てんてきゆび针,ゆかりそら变为そらそく搜索そうさく插入そうにゅう、删除てき复杂とう于树だかもちさい坏退ためへんはすげんじゅたい可能かのう形成けいせいへんはす二元樹的問題可以經由樹高改良後的平衡へいこうじゅはたさがせひろ插入そうにゅう、刪除てき時間じかん複雜ふくざつ維持いじざい,如AVL树红黑树ひとし

二叉查找树的查找算法[编辑]

ざいまた查找树bちゅう查找xてき過程かていため

  1. わかbそらじゅのり搜索そうさく失敗しっぱいいやのり
  2. わかxとう於bてき節點せってんてきすうよりどころいき值,のり查找成功せいこうそく
  3. わかxしょう於bてき節點せってんてきすうよりどころいき值,のり搜索そうさくひだりじゅそく
  4. 查找右子ゆうこ树。
Status SearchBST(BiTree T, KeyType key, BiTree f, BiTree &p) {
    // ざいゆび针Tしょゆび二叉查找树中递归地查找其關键字等於keyてきすうよりどころ元素げんそわか查找成功せいこう
    // すなわちゆび针p指向しこう該數よりどころ元素げんそ節點せってん,并返かいTRUE,いやのりゆび指向しこう查找みちじょう訪問ほうもんてき最後さいご
    // いち節點せってん并返かいFALSE,ゆび针f指向しこうTてきそうおや,其初はじめ调用值為NULL
    if (!T) { // 查找成功せいこう
        p = f;
        return false;
    } else if (key == T->data.key) { // 查找成功せいこう
        p = T;
        return true;
    } else if (key < T->data.key) // ざいひだりじゅちゅう繼續けいぞく查找
        return SearchBST(T->lchild, key, T, p);
    else // ざい右子ゆうこじゅちゅう繼續けいぞく查找
        return SearchBST(T->rchild, key, T, p);
}

ざい二叉查找树插入節点的算法[编辑]

こう一个二元搜尋樹bちゅう插入そうにゅういち个節てんsてき算法さんぽう,过程为:

  1. わかbそら树,则将sしょゆび節点せってんさく为根節点せってん插入そうにゅういや则:
  2. わかs->dataとう于bてき節点せってんてきすうすえいき值,则返かいいや则:
  3. わかs->dataしょう于bてき節点せってんてきすうすえいき值,则把sしょゆび節点せってん插入そうにゅういたひだり树中,いや则:
  4. sしょゆび節点せってん插入そうにゅういた右子ゆうこ树中。(しん插入そうにゅう節點せってんそう葉子ようこ節點せってん
/* とうげんさがせひろじゅTちゅう存在そんざい关键とう于e.keyてきすうすえ元素げんそ时,插入そうにゅうe并返かいTRUE,いや则返かい FALSE */
Status InsertBST(BiTree *&T, ElemType e) {
    if (!T) {
        s = new BiTNode;
        s->data = e;
        s->lchild = s->rchild = NULL;
        T = s; // 插節てん*s为新てき结点
    } else if (e.key == T->data.key)
        return false;// 关键とう于e.keyてきすうすえ元素げんそかえしかい錯誤さくご
    if (e.key < T->data.key)
        InsertBST(T->lchild, e);  // はた e 插入そうにゅうひだりじゅ
    else if (e.key > T->data.key)
        InsertBST(T->rchild, e);  // はた e 插入そうにゅうみぎじゅ
    return true;
}

ざい二叉查找树删除结点的算法[编辑]

删除いち个有ひだり右子ゆうこ树的节点

ざい二叉查找树删去一个结点,ふん三种情况讨论:

  1. わか*p结点为叶结点,そくPL(ひだり树)PR(右子ゆうこ树)ひとし为空树。よし于删去かのう结点不破ふわ坏整棵树てき结构,则只需修あらため其双亲结てんてきゆび针即
  2. わか*p结点ただゆうひだり树PLある右子ゆうこ树PR,此时ただようれいPLあるPR直接ちょくせつなり为其そう亲结てん*fてきひだり树(とう*pひだり树)ある右子ゆうこ树(とう*p右子ゆうこ树)そくさく此修あらため不破ふわ坏二叉查找树的特性。
  3. わか*p结点てきひだり树和右子ゆうこ树均不空ふくうざい删去*pきさき,为保持ほじ其它元素げんそ间的しょう位置いち变,按中じょへん保持ほじゆうじょ进行调整,以有两种做法:其一れい*pてきひだり树为*fてきひだり/みぎ*p*fてきひだり树还右子ゆうこ树而じょう树,*s为*pひだり树的さいみぎてき结点,而*pてき右子ゆうこ树为*sてき右子ゆうこ树;其二そのじれい*pてき直接ちょくせつぜん驱(in-order predecessor)ある直接ちょくせつきさき继(in-order successor)がえだい*p,しかきさきさい从二叉查找树中删去它的直接前驱(ある直接ちょくせつきさき继)。

ざい二叉查找树上删除一个结点的算法如下:

Status DeleteBST(BiTree *T, KeyType key) {
    // わかまた查找树Tちゅう存在そんざい关键とう于keyてきすうすえ元素げんそ时,则删じょ该数すえ元素げんそ,并返かい
    // TRUE;いや则返かいFALSE
    if (!T)
        return false; //存在そんざい关键とう于keyてきすうすえ元素げんそ
    else {
        if (key == T->data.key)   //   找到关键とう于keyてきすうすえ元素げんそ
            return Delete(T);
        else if (key < T->data.key)
            return DeleteBST(T->lchild, key);
        else
            return DeleteBST(T->rchild, key);
    }
}

Status Delete(BiTree *&p) {
    // 该节てん为叶节点,直接ちょくせつ删除
    BiTree *q, *s;
    if (!p->rchild && !p->lchild) {
        delete p;
        p = NULL;  // Status Delete(BiTree *&p) よう&才能さいのう使P指向しこうNULL
    } else if (!p->rchild) { // 右子ゆうこ树空则只需重せっ它的ひだり
        q = p->lchild;
        /*
        p->data = p->lchild->data;
        p->lchild=p->lchild->lchild;
        p->rchild=p->lchild->rchild;
        */
        p->data = q->data;
        p->lchild = q->lchild;
        p->rchild = q->rchild;
        delete q;
    } else if (!p->lchild) { // ひだり树空ただ需重せっ它的右子ゆうこ
        q = p->rchild;
        /*
        p->data = p->rchild->data;
        p->lchild=p->rchild->lchild;
        p->rchild=p->rchild->rchild;
        */
        p->data = q->data;
        p->lchild = q->lchild;
        p->rchild = q->rchild;
        delete q;
    } else { // 左右さゆう树均不空ふくう
        q = p;
        s = p->lchild;
        while (s->rchild) {
            q = s;
            s = s->rchild;
        } // 转左,しかきさきこうみぎいたつき
        p->data = s->data;  // s指向しこう删结てんてきぜん驱”
        if (q != p)
            q->rchild = s->lchild;  // じゅうせっ*qてき右子ゆうこ
        else
            q->lchild = s->lchild;  // じゅうせっ*qてきひだり
        delete s;
    }
    return true;
}

ざいC语言中有ちゅうう些编译器支持しじstruct Node 节点分配ぶんぱいそら间,こえしょう这是一个不完全的结构,使用しよういち指向しこうNodeてきゆび为之分配ぶんぱいそら间。

  • 如:sizeof( Probe )Probeさくまた树节点在てんざいtypedefちゅうてい义的ゆび针。

Python实现:

def find_min(self):   # Gets minimum node (leftmost leaf) in a subtree
    current_node = self
    while current_node.left_child:
        current_node = current_node.left_child
    return current_node

def replace_node_in_parent(self, new_value=None):
    if self.parent:
        if self == self.parent.left_child:
            self.parent.left_child = new_value
        else:
            self.parent.right_child = new_value
    if new_value:
        new_value.parent = self.parent

def binary_tree_delete(self, key):
    if key < self.key:
        self.left_child.binary_tree_delete(key)
    elif key > self.key:
        self.right_child.binary_tree_delete(key)
    else: # delete the key here
        if self.left_child and self.right_child: # if both children are present
            successor = self.right_child.find_min()
            self.key = successor.key
            successor.binary_tree_delete(successor.key)
        elif self.left_child:   # if the node has only a *left* child
            self.replace_node_in_parent(self.left_child)
        elif self.right_child:  # if the node has only a *right* child
            self.replace_node_in_parent(self.right_child)
        else: # this node has no children
            self.replace_node_in_parent(None)

二叉查找树的遍历[编辑]

ちゅうじょへん历(in-order traversal)二叉查找树的Pythonだい码:

def traverse_binary_tree(node, callback):
    if node is None:
        return
    traverse_binary_tree(node.leftChild, callback)
    callback(node.value)
    traverse_binary_tree(node.rightChild, callback)

はいじょあるしょう构造)一棵二叉查找树[编辑]

もちい一组数值建造一棵二叉查找树的同时,也把这组すう值进ぎょうりょうはいじょ。其最时间复杂れい如,わか该组すう值已经是ゆうじょてき(从小いただい),则建造けんぞう出来できてき二叉查找树的所有节点,ぼつゆうひだり树。平衡へいこう二叉查找树可以克服上述缺点,其时间复杂度为O(nlog n)。一方いっぽうめん,树排じょてき问题使とくCPU Cache性能せいのう较差,とく别是とう节点动态ないそん分配ぶんぱい时。而堆はいじょてきCPU Cache性能せいのう较好。另一方面ほうめん,树排じょさい优的增量ぞうりょうはいじょ(incremental sorting)算法さんぽう保持ほじ一个数值序列的有序性。

def build_binary_tree(values):
    tree = None
    for v in values:
        tree = binary_tree_insert(tree, v)
    return tree

def get_inorder_traversal(root):
    '''
    Returns a list containing all the values in the tree, starting at *root*.
    Traverses the tree in-order(leftChild, root, rightChild).
    '''
    result = []
    traverse_binary_tree(root, lambda element: result.append(element))
    return result

二叉查找树性能分析[编辑]

まい个结てんてき为该结点てき层次すうさい坏情况下,とうさききさき插入そうにゅうてき关键ゆうじょ时,构成てき二叉查找树蜕变为单支树,树的深度しんど,其平均へいきん查找长度为顺序查找しょうどう),さいこのみてきじょう况是二叉查找树的形态和折半查找的判定树相同,其平均へいきん查找长度なりせい)。

二叉查找树的优化[编辑]

一般いっぱんてき二叉查找树的查询复杂度取决于目标结点到树根的距离(そく深度しんど),いん此当结点てき深度しんど普遍ふへん较大时,查询てきひとし摊复杂度かいじょうます。为了实现さらだかこうてき查询,产生りょう平衡へいこうざい这里,平衡へいこうゆび所有しょゆうかのうてき深度しんど趋于平衡へいこうさら广义てきゆびざい树上所有しょゆう可能かのう查找てきひとし摊复杂度へんひく。请参见主条目じょうもく平衡へいこう

まいり[编辑]

外部がいぶ链接[编辑]