最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python利用treap實(shí)現(xiàn)雙索引的方法

 更新時(shí)間:2021年09月14日 09:17:06   作者:陳屹  
所遍歷的元素一定是遞增(小堆)或是遞減(大堆)關(guān)系,但是我們無(wú)法得知左子樹(shù)與右子樹(shù)兩部分節(jié)點(diǎn)的排序關(guān)系。本文就來(lái)講講算法和數(shù)據(jù)結(jié)構(gòu)共同滿(mǎn)足一組特性,感興趣的小伙伴請(qǐng)參考下面文章的內(nèi)容

前言:

在很多應(yīng)用場(chǎng)景下,我們不但需要堆的特性,例如快速知道數(shù)據(jù)最大值或最小值,同時(shí)還需要知道元素的排序信息,因此本節(jié)我們看看如何實(shí)現(xiàn)魚(yú)和熊掌如何兼得。假設(shè)我們有一系列數(shù)據(jù),它的元素由兩部分組成,一部分對(duì)應(yīng)商品的名稱(chēng),其類(lèi)型為字符串,一部分對(duì)應(yīng)商品的貨存數(shù)量,類(lèi)型為整形,我們既需要將商品根據(jù)其名稱(chēng)排序,同時(shí)我們又需要快速查詢(xún)當(dāng)前貨存最小的商品,我們?nèi)绾卧O(shè)計(jì)相應(yīng)的算法和數(shù)據(jù)結(jié)構(gòu)來(lái)滿(mǎn)足這樣特性呢。

舉個(gè)例子,如下圖:

從上圖看,它對(duì)應(yīng)元素字符串是排序二叉樹(shù),因此根節(jié)點(diǎn)左子樹(shù)對(duì)應(yīng)元素的字符串都小于根字符串,同時(shí)右子樹(shù)對(duì)應(yīng)的字符串都大于根節(jié)點(diǎn)字符串,同時(shí)每個(gè)元素還對(duì)應(yīng)著相應(yīng)商品的貨存數(shù)量,我們需要及時(shí)掌握當(dāng)前貨存最少的商品,這樣才能在其耗盡之前迅速補(bǔ)貨。但是從上圖可以看到,要保證字符串的排序性就得犧牲對(duì)于商品數(shù)量的小堆性質(zhì),例如上圖中water對(duì)應(yīng)的貨存與wine對(duì)應(yīng)的貨存違背了小堆的性質(zhì),現(xiàn)在問(wèn)題是如何在保證字符串排序的情況下,確保數(shù)量同時(shí)能滿(mǎn)足小堆性質(zhì)。

首先我們先定義一下數(shù)據(jù)結(jié)構(gòu):

class Node: 
    def __init__(self, key: str, priority: float): 
        self._key = key 
        self._priority = priority 
        self._left: Node = None 
        self._right: Node = None 
        self._parent: Node = None 
 
    @property 
    def left(self): 
        return self._left 
 
    @property 
    def right(self): 
        return self._right 
 
    @property 
    def parent(self): 
        return self._parent 
 
    @left.setter 
    def left(self, node): 
        self._left = node 
        if node is not None: 
            node.parent = self 
 
    @right.setter 
    def right(self, node): 
        self._right = node 
        if node is not None: 
            node.parent = self 
 
    @parent.setter 
    def parent(self, node): 
        self._parent = node 
 
    def is_root(self) -> bool: 
        if self.parent is None: 
            return True 
        return False 
 
    def __repr__(self): 
        return "({}, {})".format(self._key, self._priority) 
 
    def __str__(self): 
        repr_str: str = "" 
        repr_str += repr(self) 
        if self.parent is not None: 
            repr_str += " parent: " + repr(self.parent) 
        else: 
            repr_str += " parent: None" 
 
        if self.left is not None: 
            repr_str += " left: " + repr(self.left) 
        else: 
            repr_str += " left: None" 
 
        if self.right is not None: 
            repr_str += " right: " + repr(self.right) 
        else: 
            repr_str += " right: None" 
 
        return repr_str 
 
class Treap: 
    def  __init__(self): 
        self.root : Node = None 

當(dāng)前問(wèn)題是,當(dāng)上圖所示的矛盾出現(xiàn)時(shí),我們?nèi)绾握{(diào)整,使得字符串依然保持排序性質(zhì),同時(shí)貨存數(shù)值能滿(mǎn)足小堆性質(zhì)。我們需要根據(jù)幾種情況采取不同操作,首先看第一種,如下圖:

從上圖看到,一種情況是父節(jié)點(diǎn)與左孩子在數(shù)值上違背了堆的性質(zhì),此時(shí)我們執(zhí)行一種叫右旋轉(zhuǎn)操作,

其步驟是:

  1. Beer節(jié)點(diǎn)逆時(shí)針旋轉(zhuǎn),替換其父節(jié)點(diǎn);
  2. 父節(jié)點(diǎn)Cabbage順時(shí)針旋轉(zhuǎn),成為Beer的右孩子節(jié)點(diǎn);
  3. 原來(lái)Beer的右孩子節(jié)點(diǎn)轉(zhuǎn)變?yōu)?code>Cabbage的左孩子節(jié)點(diǎn);

完成后結(jié)果如下圖所示:

可以看到,此時(shí)字符串依然保持排序二叉樹(shù)性質(zhì),同時(shí)數(shù)值對(duì)應(yīng)的小堆性質(zhì)也得到了滿(mǎn)足。

我們看看代碼實(shí)現(xiàn):

class Treap: 
    def __init__(self): 
        self._root: Node = None 
 
    def right_rotate(self, x: Node): 
        if x is None or x.is_root() is True: 
            return 
 
        y = x.parent 
        if y.left != x:  # 必須是左孩子才能右旋轉(zhuǎn) 
            return 
 
        p = y.parent 
        if p is not None:  # 執(zhí)行右旋轉(zhuǎn) 
            if p.left == y: 
                p.left = x 
            else: 
                p.right = x 
        else: 
            self._root = x 
 
        y.left = x.right 
        x.right = y 


接下來(lái)我們構(gòu)造一些數(shù)據(jù)測(cè)試一下上面的實(shí)現(xiàn)是否正確:

def setup_right_rotate(): 
    flour: Node = Node("Flour", 10) 
    cabbage: Node = Node("Cabbage", 77) 
    beer: Node = Node("Beer", 76) 
    bacon: Node = Node("Bacon", 95) 
    butter: Node = Node("Butter", 86) 
 
    flour.parent = None 
    flour.left = cabbage 
    flour.right = None 
    cabbage.left = beer 
 
 
    beer.left = bacon 
    beer.right = butter 
 
    return flour, beer 
 
def print_treap(n: Node): 
    if n is None: 
        return 
 
    print(n) 
    print_treap(n.left) 
    print_treap(n.right) 
 
treap = Treap() 
root, x , cabbage = setup_right_rotate() 
print("---------before right rotate---------:") 
print_treap(root) 
treap.right_rotate(x) 
print("-------after right rotate-------") 
print_treap(root) 


上面代碼執(zhí)行后輸出內(nèi)容如下:

---------before right rotate---------:
(Flour, 10) parent: None left: (Cabbage, 77) right: None
(Cabbage, 77) parent: (Flour, 10) left: (Beer, 76) right: (Eggs, 129)
(Beer, 76) parent: (Cabbage, 77) left: (Bacon, 95) right: (Butter, 86)
(Bacon, 95) parent: (Beer, 76) left: None right: None
(Butter, 86) parent: (Beer, 76) left: None right: None
(Eggs, 129) parent: (Cabbage, 77) left: None right: None
-------after right rotate-------
(Flour, 10) parent: None left: (Beer, 76) right: None
(Beer, 76) parent: (Flour, 10) left: (Bacon, 95) right: (Cabbage, 77)
(Bacon, 95) parent: (Beer, 76) left: None right: None
(Cabbage, 77) parent: (Beer, 76) left: (Butter, 86) right: (Eggs, 129)
(Butter, 86) parent: (Cabbage, 77) left: None right: None
(Eggs, 129) parent: (Cabbage, 77) left: None right: None

對(duì)比右旋轉(zhuǎn)前后輸出的二叉樹(shù)看,旋轉(zhuǎn)后的二叉樹(shù)打印信息的確跟上面我們旋轉(zhuǎn)后對(duì)應(yīng)的圖像是一致的。接下來(lái)我們實(shí)現(xiàn)左旋轉(zhuǎn),先把上圖中cabbage節(jié)點(diǎn)對(duì)應(yīng)的值改成75,這樣它與父節(jié)點(diǎn)就違背了小堆性質(zhì):

 

我們要做的是:

  1. cabbage節(jié)點(diǎn)向“左”旋轉(zhuǎn)到beer的位置;
  2. beer的父節(jié)點(diǎn)設(shè)置為cabbage;
  3. beer的右孩子設(shè)置為cabbage的左孩子;
  4. cabbage的左孩子變成beer;左旋轉(zhuǎn)后二叉樹(shù)

成形如下:

 

從上圖看,左旋轉(zhuǎn)后,字符串依然保持二叉樹(shù)排序性,同時(shí)數(shù)值的排放也遵守小堆原則,我們看相應(yīng)的代碼實(shí)現(xiàn):

class Treap: 
   ... 
 
    def left_rotate(self, x : Node): 
        if x is None or x.is_root() is True: 
            return 
 
        y = x.parent 
        if y.right is not x: # 只有右孩子才能左旋轉(zhuǎn) 
            return 
 
        p = y.parent 
        if p is not None: 
            if p.left is y: 
                p.left = x 
            else: 
                p.right = x 
        else: 
            self._root = x 
 
        y.right = x.left 
        x.left = y 


為了測(cè)試上面代碼實(shí)現(xiàn),我們首先把cabbage的值修改,然后調(diào)用上面代碼:

cabbage._priority = 75 
print("-------before left rotate--------") 
print_treap(root) 
treap.left_rotate(cabbage) 
print("-------after left rotate---------") 
print_treap(root) 


代碼運(yùn)行后輸出結(jié)果為:

-------before left rotate--------
(Flour, 10) parent: None left: (Beer, 76) right: None
(Beer, 76) parent: (Flour, 10) left: (Bacon, 95) right: (Cabbage, 75)
(Bacon, 95) parent: (Beer, 76) left: None right: None
(Cabbage, 75) parent: (Beer, 76) left: (Butter, 86) right: (Eggs, 129)
(Butter, 86) parent: (Cabbage, 75) left: None right: None
(Eggs, 129) parent: (Cabbage, 75) left: None right: None
-------after left rotate---------
(Flour, 10) parent: None left: (Cabbage, 75) right: None
(Cabbage, 75) parent: (Flour, 10) left: (Beer, 76) right: (Eggs, 129)
(Beer, 76) parent: (Cabbage, 75) left: (Bacon, 95) right: (Butter, 86)
(Bacon, 95) parent: (Beer, 76) left: None right: None
(Butter, 86) parent: (Beer, 76) left: None right: None
(Eggs, 129) parent: (Cabbage, 75) left: None right: None

輸出結(jié)果的描述與上圖左旋轉(zhuǎn)后的結(jié)果是一致的。由于Treap相對(duì)于元素的key是排序二叉樹(shù),因此在給定一個(gè)字符串后,我們很容易查詢(xún)字符串是否在Treap中,其本質(zhì)就是排序二叉樹(shù)的搜索,其實(shí)現(xiàn)我們暫時(shí)忽略。

雖然查詢(xún)很簡(jiǎn)單,但是插入節(jié)點(diǎn)則稍微麻煩,因?yàn)椴迦牒?,新?jié)點(diǎn)與其父節(jié)點(diǎn)可能會(huì)違背小堆性質(zhì),因此在完成插入后,我們還需使用上面實(shí)現(xiàn)的左旋轉(zhuǎn)或右旋轉(zhuǎn)來(lái)進(jìn)行調(diào)整。

到此這篇關(guān)于Python使用treap實(shí)現(xiàn)雙索引的方法的文章就介紹到這了,更多相關(guān)Python使用treap實(shí)現(xiàn)雙索引內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Django與FastAPI的選擇區(qū)別深入剖析

    Django與FastAPI的選擇區(qū)別深入剖析

    這篇文章主要為大家介紹了Django與FastAPI的選擇區(qū)別深入剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • pygame實(shí)現(xiàn)井字棋之第二步邏輯實(shí)現(xiàn)

    pygame實(shí)現(xiàn)井字棋之第二步邏輯實(shí)現(xiàn)

    這篇文章主要介紹了pygame實(shí)現(xiàn)井字棋之第二步邏輯實(shí)現(xiàn),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)python的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-05-05
  • Python中subprocess的簡(jiǎn)單使用示例

    Python中subprocess的簡(jiǎn)單使用示例

    這篇文章主要介紹了Python中subprocess的簡(jiǎn)單使用示例,是Python進(jìn)程方面處理的相關(guān)重要知識(shí),需要的朋友可以參考下
    2015-07-07
  • selenium+python實(shí)現(xiàn)基本自動(dòng)化測(cè)試的示例代碼

    selenium+python實(shí)現(xiàn)基本自動(dòng)化測(cè)試的示例代碼

    這篇文章主要介紹了selenium+python實(shí)現(xiàn)基本自動(dòng)化測(cè)試的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • html網(wǎng)頁(yè)調(diào)用后端python代碼的方法實(shí)例

    html網(wǎng)頁(yè)調(diào)用后端python代碼的方法實(shí)例

    html頁(yè)面中確實(shí)能夠調(diào)用python程序,不過(guò)只能調(diào)“一點(diǎn)點(diǎn)”,下面這篇文章主要給大家介紹了關(guān)于html網(wǎng)頁(yè)調(diào)用后端python代碼的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • 詳解Python的數(shù)據(jù)庫(kù)操作(pymysql)

    詳解Python的數(shù)據(jù)庫(kù)操作(pymysql)

    這篇文章主要介紹了Python的數(shù)據(jù)庫(kù)操作(pymysql),非常不錯(cuò),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下
    2019-04-04
  • Python實(shí)現(xiàn)簡(jiǎn)單的索引排序與搜索功能

    Python實(shí)現(xiàn)簡(jiǎn)單的索引排序與搜索功能

    這篇文章主要介紹了Python實(shí)現(xiàn)簡(jiǎn)單的索引排序與搜索功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • python問(wèn)題匯總之pycharm查找不到安裝的庫(kù)解決

    python問(wèn)題匯總之pycharm查找不到安裝的庫(kù)解決

    這篇文章主要給大家介紹了關(guān)于python問(wèn)題匯總之pycharm查找不到安裝庫(kù)的解決方法,PyCharm是一款非常流行的Python集成開(kāi)發(fā)環(huán)境(IDE),它提供了豐富的功能和插件,可以幫助程序員更高效地編寫(xiě)Python代碼,需要的朋友可以參考下
    2023-09-09
  • Python2比較當(dāng)前圖片跟圖庫(kù)哪個(gè)圖片相似的方法示例

    Python2比較當(dāng)前圖片跟圖庫(kù)哪個(gè)圖片相似的方法示例

    這篇文章主要介紹了Python2比較當(dāng)前圖片跟圖庫(kù)哪個(gè)圖片相似的方法,結(jié)合實(shí)例形式分析了Python文件目錄操作及圖形運(yùn)算相關(guān)使用技巧,需要的朋友可以參考下
    2019-09-09
  • python非阻塞式后臺(tái)如何運(yùn)行bat腳本

    python非阻塞式后臺(tái)如何運(yùn)行bat腳本

    這篇文章主要介紹了python非阻塞式后臺(tái)如何運(yùn)行bat腳本問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06

最新評(píng)論

枞阳县| 得荣县| 琼海市| 库车县| 南昌市| 皮山县| 赣州市| 昌乐县| 武宁县| 秦皇岛市| 丰台区| 永胜县| 义马市| 新巴尔虎左旗| 卓尼县| 祁阳县| 乌拉特前旗| 镶黄旗| 阳新县| 普宁市| 得荣县| 合川市| 海丰县| 阿勒泰市| 白城市| 永福县| 屏南县| 无极县| 韶山市| 吴川市| 忻州市| 湖口县| 文登市| 昌乐县| 桃源县| 兴城市| 济南市| 象州县| 瑞金市| 沛县| 蒙阴县|