超簡(jiǎn)單二叉樹(shù)python實(shí)現(xiàn)及二叉樹(shù)排序

二叉樹(shù)其實(shí)直觀理解起來(lái)還算比較簡(jiǎn)單若专,它是一個(gè)樹(shù)結(jié)構(gòu)久信,也就是層級(jí)結(jié)構(gòu)窖杀,每一層每一個(gè)父節(jié)點(diǎn)最多有兩個(gè)子節(jié)點(diǎn)。二叉樹(shù)用來(lái)搜索效果不錯(cuò)入篮,因?yàn)橹灰WC左節(jié)點(diǎn)比父節(jié)點(diǎn)小陈瘦,右節(jié)點(diǎn)比父節(jié)點(diǎn)大,那么搜索下來(lái)時(shí)間復(fù)雜度其實(shí)就是很理想的O(logn)潮售。

但是對(duì)于一個(gè)python新手來(lái)說(shuō),二叉樹(shù)也是比較難實(shí)現(xiàn)的锅风,因?yàn)榘蠢碚f(shuō)樹(shù)結(jié)構(gòu)其實(shí)應(yīng)該是一種“鏈表”酥诽,但是python里面似乎可能好像沒(méi)有這種結(jié)構(gòu),Java是有的(有人開(kāi)始罵python是一門很low的語(yǔ)言了)……所以一開(kāi)始我理解起來(lái)還很困難皱埠!這個(gè)怎么能把樹(shù)上的每個(gè)節(jié)點(diǎn)串起來(lái)啊肮帐,怎么表示關(guān)系啊,然后我去刷stackoverflow边器,還真的慢慢地理解了它(的基礎(chǔ))训枢。

1. 建立節(jié)點(diǎn)

如上文所述,二叉樹(shù)的結(jié)構(gòu)就是每一個(gè)父節(jié)點(diǎn)都有不超過(guò)兩個(gè)子節(jié)點(diǎn)忘巧。那么對(duì)于二叉樹(shù)的每個(gè)點(diǎn)建一個(gè)類恒界,這個(gè)類中規(guī)定三個(gè)屬性:節(jié)點(diǎn)自身的值value,節(jié)點(diǎn)的左子節(jié)點(diǎn)值left砚嘴,節(jié)點(diǎn)的右子節(jié)點(diǎn)值right十酣。對(duì)于每一個(gè)點(diǎn)而言涩拙,在初始化的時(shí)候都把一個(gè)值賦給它自己,同時(shí)左右子節(jié)點(diǎn)置為空耸采。這個(gè)很好理解吧兴泥?葉子節(jié)點(diǎn)的左右子節(jié)點(diǎn)就會(huì)一直為空了,但是

代碼:

class TreeNode(object):
    def __init__(self,value):
        self.value = value
        self.left = None
        self.right = None

2. 建立搜索樹(shù)

現(xiàn)在我們有了點(diǎn)虾宇,看起來(lái)很簡(jiǎn)單,但是該怎么把樹(shù)建起來(lái)呢嘱朽?

二叉樹(shù)建樹(shù)其實(shí)就像上面說(shuō)的燥翅,是一個(gè)很簡(jiǎn)單明確的過(guò)程森书,首先需要一個(gè)根節(jié)點(diǎn)凛膏,然后每一次新的節(jié)點(diǎn)過(guò)來(lái)猖毫,就跟根節(jié)點(diǎn)比較吁断,比它小就作為左子節(jié)點(diǎn)仔役,比它大就作為右子節(jié)點(diǎn),然后依次跟下一層比較任柜,直到自己成為葉子節(jié)點(diǎn)停止宙地。

算法的要點(diǎn)是利用遞歸算法 recursion宅粥,說(shuō)實(shí)話靠我自己想可能還是太難太抽象了點(diǎn)粹胯。但是如果你要去領(lǐng)會(huì)它的意思风纠,做得也就是這件事:

class BinaryTree(object):
    def insert(self,root, node):
        if root is None:
            return node
        if node.value < root.value:
            root.left = self.insert(root.left, node)
        else:
            root.right = self.insert(root.right, node)
        return root

我們定義了一個(gè)新的類 二叉樹(shù)竹观,這個(gè)類里面只有一個(gè)insert方法臭增,就是插入一個(gè)新的節(jié)點(diǎn)到已生成的樹(shù)中誊抛。這個(gè)方法的記憶點(diǎn)有兩塊:

1.輸入?yún)?shù):

此處的參數(shù)應(yīng)該是已生成的樹(shù)節(jié)點(diǎn)拗窃,和準(zhǔn)備加入的新節(jié)點(diǎn)随夸,這兩者的類型都需要是剛剛定義的帶有左右子節(jié)點(diǎn)屬性的類宾毒;

2.遞歸诈铛,采用三個(gè)條件判斷:

如果當(dāng)前節(jié)點(diǎn)為空就返回新的節(jié)點(diǎn)幢竹;如果當(dāng)前節(jié)點(diǎn)不為空且比新的節(jié)點(diǎn)值大,那么就遞歸地判斷當(dāng)前節(jié)點(diǎn)的左子節(jié)點(diǎn)和新節(jié)點(diǎn)的關(guān)系,直到當(dāng)前節(jié)點(diǎn)為空咬荷;比新的節(jié)點(diǎn)小就遞歸地判斷當(dāng)前節(jié)點(diǎn)的左子節(jié)點(diǎn)和新節(jié)點(diǎn)的關(guān)系幸乒,直到當(dāng)前節(jié)點(diǎn)為空返回罕扎。

3. 生成二叉搜索樹(shù):

那么下面我們就用一個(gè)循環(huán)語(yǔ)句來(lái)生成一棵二叉搜索樹(shù)吧腔召。

root = Node(5)
tree = BinaryTree()

for i in [2,11,7,3,9,8,4,6,1]:
    tree.insert(root,Node(i))

現(xiàn)在基本上大功告成了臀蛛!當(dāng)你興奮地敲下run之后浊仆,當(dāng)當(dāng)當(dāng)當(dāng)——

程序運(yùn)行完抡柿,啥也沒(méi)顯示洲劣,就完了闪檬。

那是因?yàn)槲覀儧](méi)有把樹(shù)“遍歷”地展示出來(lái)粗悯,python有一個(gè)二叉樹(shù)庫(kù) binarytree样傍,可以用pip安裝衫哥,允許你打印出樹(shù)的結(jié)構(gòu),可以用非常直觀的方式來(lái)構(gòu)建二叉樹(shù),看看人家的示例:

>>> from binarytree import Node
>>> root = Node(3)
>>> root.left = Node(2)
>>> root.right = Node(7)
>>> root.left.left = Node(4)
>>> root.left.right = Node(1)
>>> print(root)

    __3
   /   \
  2     7
 / \
4   1

4. 二叉樹(shù)的三種遍歷算法及排序

當(dāng)我們已經(jīng)有一個(gè)二叉樹(shù)的時(shí)候膛锭,有哪幾種方式來(lái)遍歷它呢初狰?

這是一個(gè)面試常見(jiàn)考點(diǎn)奢入,相信很多小伙伴腦子里已經(jīng)蹦出了答案:前序遍歷腥光,中序遍歷议双,后序遍歷

那么哪種遍歷方法可以使二叉樹(shù)輸出有序呢聋伦?

中序遍歷

在說(shuō)到二叉樹(shù)遍歷的前序觉增,中序和后序的時(shí)候逾礁,需要牢牢記住,這里的前砾嫉,中焕刮,后的順序配并,都是相對(duì)于節(jié)點(diǎn)本身而言的溉旋。所以“前序遍歷”實(shí)際上的意思是:把遍歷我這個(gè)父節(jié)點(diǎn)先放到前面嫉髓,然后再左子節(jié)點(diǎn)恕沫,然后再右子節(jié)點(diǎn),一直要保證這個(gè)順序偷霉。中序遍歷就是把遍歷父節(jié)點(diǎn)放在中間去進(jìn)行叙身,先左子節(jié)點(diǎn)信轿,然后再右子節(jié)點(diǎn)财忽,子節(jié)點(diǎn)的遍歷需要注意的是這個(gè)過(guò)程也是遞歸的。后序遍歷呢隶校,就是先左子節(jié)點(diǎn),然后右子節(jié)點(diǎn)舞终,最后再遍歷父節(jié)點(diǎn)。

所以,自然满俗,由于二叉樹(shù)本身生成的時(shí)候的特性,再遍歷的時(shí)候如果采用中序辕万,就能夠保證整個(gè)輸出是從小到大有序的了醉途。

所以我們定義三個(gè)新的函數(shù)來(lái)表示這三種遍歷方法:

# 前序遍歷
def pre_order_print(node):
    # self -- left -- right
    print(node.value,end=' ')
    if node.left:
        pre_order_print(node.left)
    if node.right:
        pre_order_print(node.right)
# 中序遍歷     
def mid_order_print(node):
    # left --self -- right
    if node.left:
        mid_order_print(node.left)
    print(node.value,end=' ')
    if node.right:
        mid_order_print(node.right)
# 后序遍歷     
def after_order_print(node):
    # left-- right--self
    if node.left:
        after_order_print(node.left)
    if node.right:
        after_order_print(node.right)
    print(node.value, end=' ')

  1. 完整的程序
class Node(object):
    def __init__(self,value):
        self.value = value
        self.left = None
        self.right = None

class BinaryTree(object):
    def insert(self, root, node):
        if root is None:
            return node
        if node.value < root.value:
            root.left = self.insert(root.left, node)
        else:
            root.right = self.insert(root.right, node)

        return root

def pre_order_print(node):
    # self -- left -- right
    print(node.value,end=' ')
    if node.left:
        pre_order_print(node.left)
    if node.right:
        pre_order_print(node.right)
        
def mid_order_print(node):
    # mid --self -- right
    if node.left:
        mid_order_print(node.left)
    print(node.value,end=' ')
    if node.right:
        mid_order_print(node.right)

def after_order_print(node):
    # left-- right--self
    if node.left:
        after_order_print(node.left)
    if node.right:
        after_order_print(node.right)
    print(node.value, end=' ')

root = Node(5)

tree = BinaryTree()

for i in [2,11,7,3,9,8,4,6,1]:
    tree.insert(root,Node(i))
mid_order_print(root)

這樣輸出的結(jié)果就是有序的了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末再沧,一起剝皮案震驚了整個(gè)濱河市淤堵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖东臀,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赁濒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡玉组,警方通過(guò)查閱死者的電腦和手機(jī)绒障,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門庐镐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)必逆,“玉大人,你說(shuō)我怎么就攤上這事揽乱∶迹” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵凰棉,是天一觀的道長(zhǎng)损拢。 經(jīng)常有香客問(wèn)我,道長(zhǎng)撒犀,這世上最難降的妖魔是什么福压? 我笑而不...
    開(kāi)封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮或舞,結(jié)果婚禮上荆姆,老公的妹妹穿的比我還像新娘。我一直安慰自己映凳,他們只是感情好胆筒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著魏宽,像睡著了一般腐泻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上队询,一...
    開(kāi)封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天派桩,我揣著相機(jī)與錄音,去河邊找鬼蚌斩。 笑死铆惑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播员魏,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼丑蛤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了撕阎?” 一聲冷哼從身側(cè)響起受裹,我...
    開(kāi)封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎虏束,沒(méi)想到半個(gè)月后棉饶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡镇匀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年照藻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汗侵。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡幸缕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出晰韵,到底是詐尸還是另有隱情发乔,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布宫屠,位于F島的核電站列疗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏浪蹂。R本人自食惡果不足惜抵栈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坤次。 院中可真熱鬧古劲,春花似錦、人聲如沸缰猴。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)滑绒。三九已至闷堡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疑故,已是汗流浹背杠览。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纵势,地道東北人踱阿。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓管钳,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親软舌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子才漆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容