算法總結(jié)-Python 二

樹的列表表示

def BinaryTree(r):
    return [r, [], []]

def insertLeft(root,newBranch):
    t = root.pop(1)
    if len(t) > 1:
        root.insert(1,[newBranch,t,[]])
    else:
        root.insert(1,[newBranch, [], []])
    return root

def insertRight(root,newBranch):
    t = root.pop(2)
    if len(t) > 1:
        root.insert(2,[newBranch,[],t])
    else:
        root.insert(2,[newBranch,[],[]])
    return root

def getRootVal(root):
    return root[0]

def setRootVal(root,newVal):
    root[0] = newVal

def getLeftChild(root):
    return root[1]

def getRightChild(root):
    return root[2]

r = BinaryTree(3)
insertLeft(r,4)
insertLeft(r,5)
insertRight(r,6)
insertRight(r,7)
l = getLeftChild(r)
print(l)

setRootVal(l,9)
print(r)
insertLeft(l,11)
print(r)
print(getRightChild(getRightChild(r)))

樹的node表示

class BinaryTree:
    def __init__(self, rootObj):
        self.key = rootObj
        self.leftChild = None
        self.rightChild = None

    def insertLeft(self, newNode):
        if self.leftChild == None:
            self.leftChild = BinaryTree(newNode)
        else:
            t = BinaryTree(newNode)
            t.leftChild = self.leftChild
            self.leftChild = t

    def insertRight(self, newNode):
        if self.rightChild == None:
            self.rightChild = BinaryTree(newNode)
        else:
            t = BinaryTree(newNode)
            t.rightChild = self.rightChild
            self.rightChild = t

    def getRightChild(self):
        return self.rightChild

    def getLeftChild(self):
        return self.leftChild

    def setRootVal(self, obj):
        self.key = obj

    def getRootVal(self):
        return self.key


def buildTree():
    root_tree = BinaryTree('a')

    root_tree.insertRight('c')
    root_tree.insertLeft('b')
    root_tree.getLeftChild().insertRight('d')
    root_tree.getRightChild().insertLeft('e')
    root_tree.getRightChild().insertRight('f')

    return root_tree

ttree = buildTree()

上面程序生成樹為

image.png
樹的遍歷

中文翻譯稿 偷個(gè)懶,加快點(diǎn)進(jìn)度

二叉樹搜索
image.png

二叉搜索樹有個(gè)基特征遍尺,左邊的節(jié)點(diǎn)比父節(jié)點(diǎn)小蔬啡,右邊節(jié)點(diǎn)比父節(jié)點(diǎn)大。下面一一分析實(shí)現(xiàn)一個(gè)基本二叉樹常用操作思考過(guò)程:
1血久、創(chuàng)建兩個(gè)類,一個(gè)實(shí)現(xiàn)節(jié)點(diǎn)的常用屬性帮非,如保存child氧吐,parent等。我們實(shí)現(xiàn)的二叉樹保存的類似于字典末盔,key用來(lái)生成二叉搜索樹筑舅,對(duì)應(yīng)一個(gè)value值。

class TreeNode:
   def __init__(self,key,val,left=None,right=None,
                                       parent=None):
        self.key = key
        self.payload = val
        self.leftChild = left
        self.rightChild = right
        self.parent = parent

    def hasLeftChild(self):
        return self.leftChild

    def hasRightChild(self):
        return self.rightChild

    def isLeftChild(self):
        return self.parent and self.parent.leftChild == self

    def isRightChild(self):
        return self.parent and self.parent.rightChild == self

    def isRoot(self):
        return not self.parent

    def isLeaf(self):
        return not (self.rightChild or self.leftChild)

    def hasAnyChildren(self):
        return self.rightChild or self.leftChild

    def hasBothChildren(self):
        return self.rightChild and self.leftChild

    def replaceNodeData(self,key,value,lc,rc):
        self.key = key
        self.payload = value
        self.leftChild = lc
        self.rightChild = rc
        if self.hasLeftChild():
            self.leftChild.parent = self
        if self.hasRightChild():
            self.rightChild.parent = self

另一個(gè)類實(shí)現(xiàn)二叉搜索樹常用操作陨舱,如查找翠拣,刪除等等。這個(gè)實(shí)現(xiàn)也是最為復(fù)雜游盲,需要考慮因素很多误墓,逐步分析邦尊。先完成類的基本屬性。

class BinarySearchTree:

    def __init__(self):
        self.root = None
        self.size = 0

    def length(self):
        return self.size

    def __len__(self):
        return self.size

    def __iter__(self):
        return self.root.__iter__()

第二步优烧,完成添加新節(jié)點(diǎn)蝉揍,用put方法。分析過(guò)程:說(shuō)先看根節(jié)點(diǎn)有沒有畦娄,沒有根節(jié)點(diǎn)直接作為根節(jié)點(diǎn)又沾。有根節(jié)點(diǎn)根據(jù)大小確定位置,因?yàn)椴淮_定樹長(zhǎng)度熙卡,只能用迭代判斷(迭代是效率比較低杖刷,一般盡量不用,但不確定循環(huán)次數(shù)和為了代碼整潔驳癌,分析問(wèn)題方便使用之滑燃,威力無(wú)窮)

def put(self,key,val):
    if self.root:
        self._put(key,val,self.root)
    else:
        self.root = TreeNode(key,val)
    self.size = self.size + 1

def _put(self,key,val,currentNode):
    if key < currentNode.key:
        if currentNode.hasLeftChild():
               self._put(key,val,currentNode.leftChild)
        else:
               currentNode.leftChild = TreeNode(key,val,parent=currentNode)
    else:
        if currentNode.hasRightChild():
               self._put(key,val,currentNode.rightChild)
        else:
               currentNode.rightChild = TreeNode(key,val,parent=currentNode)

小疑問(wèn):self.root從何而來(lái),初始化中賦值不是為None了嗎,難道與__iter__(self):方法有關(guān)

第三步颓鲜,對(duì)給定鍵的值搜索表窘,和put方法一樣,也需要給定一個(gè)根節(jié)點(diǎn)甜滨,然后順著往下一次查找乐严,所以也需要判斷根節(jié)點(diǎn)有沒有。

def get(self,key):
    if self.root:
        res = self._get(key,self.root)
        if res:
               return res.payload
        else:
               return None
    else:
        return None

def _get(self,key,currentNode):
    if not currentNode:
        return None
    elif currentNode.key == key:
        return currentNode
    elif key < currentNode.key:
        return self._get(key,currentNode.leftChild)
    else:
        return self._get(key,currentNode.rightChild)

有了put和get方法衣摩,可以實(shí)現(xiàn)一些特定功能昂验,如__getitem____setitem__ __contains__

def __setitem__(self,k,v):
    self.put(k,v)
def __getitem__(self,key):
    return self.get(key)
def __contains__(self,key):
    if self._get(key,self.root):
        return True
    else:
        return False

這些都在常用的數(shù)據(jù)結(jié)構(gòu)中有實(shí)現(xiàn),每一個(gè)都有特殊的功能艾扮,如__setitem__ 使得我們可以編寫像myZipTree['Plymouth'] = 55446 這樣的 Python 語(yǔ)句既琴,就像 Python 字典一樣。
__getitem__方法泡嘴,我們可以編寫一個(gè)類似于訪問(wèn)字典的 Python 語(yǔ)句甫恩,而實(shí)際上我們使用的是二叉搜索樹,例如 z = myZipTree ['Fargo']
__contains__重載了 in 操作符磕诊,可以實(shí)現(xiàn)

if 'Northfield' in myZipTree:
    print("oom ya ya")

第四步填物,實(shí)現(xiàn)刪除纹腌,這也是最最小心的地方霎终。一個(gè)二叉搜索樹的刪除,找到刪除的節(jié)點(diǎn)位置后需要考慮左右兒子的情況

    def delete(self,key):
      if self.size > 1:
         nodeToRemove = self._get(key,self.root)
         if nodeToRemove:
             self.remove(nodeToRemove)
             self.size = self.size-1
         else:
             raise KeyError('Error, key not in tree')
      elif self.size == 1 and self.root.key == key:
         self.root = None
         self.size = self.size - 1
      else:
         raise KeyError('Error, key not in tree')

    def __delitem__(self,key):
       self.delete(key)

    def spliceOut(self):
       if self.isLeaf():
           if self.isLeftChild():
                  self.parent.leftChild = None
           else:
                  self.parent.rightChild = None
       elif self.hasAnyChildren():
           if self.hasLeftChild():
                  if self.isLeftChild():
                     self.parent.leftChild = self.leftChild
                  else:
                     self.parent.rightChild = self.leftChild
                  self.leftChild.parent = self.parent
           else:
                  if self.isLeftChild():
                     self.parent.leftChild = self.rightChild
                  else:
                     self.parent.rightChild = self.rightChild
                  self.rightChild.parent = self.parent

    def findSuccessor(self):
      succ = None
      if self.hasRightChild():
          succ = self.rightChild.findMin()
      else:
          if self.parent:
                 if self.isLeftChild():
                     succ = self.parent
                 else:
                     self.parent.rightChild = None
                     succ = self.parent.findSuccessor()
                     self.parent.rightChild = self
      return succ

    def findMin(self):
      current = self
      while current.hasLeftChild():
          current = current.leftChild
      return current

    def remove(self,currentNode):
         if currentNode.isLeaf(): #leaf
           if currentNode == currentNode.parent.leftChild:
               currentNode.parent.leftChild = None
           else:
               currentNode.parent.rightChild = None
         elif currentNode.hasBothChildren(): #interior
           succ = currentNode.findSuccessor()
           succ.spliceOut()
           currentNode.key = succ.key
           currentNode.payload = succ.payload

         else: # this node has one child
           if currentNode.hasLeftChild():
             if currentNode.isLeftChild():
                 currentNode.leftChild.parent = currentNode.parent
                 currentNode.parent.leftChild = currentNode.leftChild
             elif currentNode.isRightChild():
                 currentNode.leftChild.parent = currentNode.parent
                 currentNode.parent.rightChild = currentNode.leftChild
             else:
                 currentNode.replaceNodeData(currentNode.leftChild.key,
                                    currentNode.leftChild.payload,
                                    currentNode.leftChild.leftChild,
                                    currentNode.leftChild.rightChild)
           else:
             if currentNode.isLeftChild():
                 currentNode.rightChild.parent = currentNode.parent
                 currentNode.parent.leftChild = currentNode.rightChild
             elif currentNode.isRightChild():
                 currentNode.rightChild.parent = currentNode.parent
                 currentNode.parent.rightChild = currentNode.rightChild
             else:
                 currentNode.replaceNodeData(currentNode.rightChild.key,
                                    currentNode.rightChild.payload,
                                    currentNode.rightChild.leftChild,
                                    currentNode.rightChild.rightChild)

二叉查找樹有個(gè)最大的問(wèn)題就是容易導(dǎo)致層數(shù)特別多升薯,得看數(shù)據(jù)插入的順序莱褒,提出了平衡二叉樹,充分發(fā)揮二叉樹存在的價(jià)值涎劈。

平衡二叉樹實(shí)現(xiàn)

參考學(xué)習(xí)

圖和圖算法

圖的實(shí)現(xiàn)

1广凸、領(lǐng)接矩陣
image.png
image.png

大多元素為空阅茶,所以說(shuō)是稀疏矩陣,事實(shí)上谅海,矩陣不是一個(gè)十分有效的存儲(chǔ)稀疏數(shù)據(jù)的有效方式脸哀。

鄰接表

實(shí)現(xiàn)稀疏連接圖的更空間高效的方法是使用鄰接表。

image.png

頂點(diǎn)類的實(shí)現(xiàn)采用字典而不是列表扭吁,字典鍵是頂點(diǎn)撞蜂,值是權(quán)重。

鄰接表實(shí)現(xiàn)
class Vertex:
    def __init__(self,key):
        self.id = key
        self.connectedTo = {}

    def addNeighbor(self,nbr,weight=0):
        self.connectedTo[nbr] = weight

    def __str__(self):
        return str(self.id) + ' connectedTo: ' + str([x.id for x in self.connectedTo])

    def getConnections(self):
        return self.connectedTo.keys()

    def getId(self):
        return self.id

    def getWeight(self,nbr):
        return self.connectedTo[nbr]

定義了一個(gè)頂點(diǎn)類侥袜,該頂點(diǎn)類用字典標(biāo)識(shí)和鄰居間的鄰接關(guān)系蝌诡,即鄰居節(jié)點(diǎn)和權(quán)重。該類也完成一些通用操作枫吧,如節(jié)點(diǎn)添加浦旱,獲取ID等。

class Graph:
    def __init__(self):
        self.vertList = {}
        self.numVertices = 0

    def addVertex(self,key):
        self.numVertices = self.numVertices + 1
        newVertex = Vertex(key)
        self.vertList[key] = newVertex
        return newVertex

    def getVertex(self,n):
        if n in self.vertList:
            return self.vertList[n]
        else:
            return None

    def __contains__(self,n):
        return n in self.vertList

    def addEdge(self,f,t,cost=0):
        if f not in self.vertList:
            nv = self.addVertex(f)
        if t not in self.vertList:
            nv = self.addVertex(t)
        self.vertList[f].addNeighbor(self.vertList[t], cost)

    def getVertices(self):
        return self.vertList.keys()

    def __iter__(self):
        return iter(self.vertList.values())

創(chuàng)建上述圖程序?yàn)椋?/p>


if __name__ == '__main__':
    g = Graph()
    for i in range(6):
        g.addVertex(i)
    g.addEdge(0,1,5)
    g.addEdge(0,5,2)
    g.addEdge(1, 2, 4)
    g.addEdge(2, 3, 9)
    g.addEdge(3, 4, 7)
    g.addEdge(3, 5, 3)
    g.addEdge(4, 0, 1)
    g.addEdge(5, 4, 8)
    g.addEdge(5, 2, 1)

    for v in g:
        for w in v.getConnections():
            print "(%s ,%s)" % (v.getId(),w.getId())
字梯問(wèn)題

將單詞 “FOOL” 轉(zhuǎn)換為單詞 “SAGE”九杂。 在字梯中你通過(guò)改變一個(gè)字母逐漸發(fā)生變化颁湖。 在每一步,你必須將一個(gè)字變換成另一個(gè)字例隆。有點(diǎn)像格雷碼爷狈。


image.png

從文件中讀入單詞,若兩兩比較裳擎,則當(dāng)單詞數(shù)多時(shí)比較次數(shù)暴增涎永,可以使用以下的辦法

image.png

假設(shè)我們有大量的桶,每個(gè)桶在外面有一個(gè)四個(gè)字母的單詞鹿响,除了標(biāo)簽中的一個(gè)字母已經(jīng)被下劃線替代羡微。例如,看 Figure 2惶我,我們可能有一個(gè)標(biāo)記為 “pop” 的桶妈倔。當(dāng)我們處理列表中的每個(gè)單詞時(shí),我們使用 “” 作為通配符比較每個(gè)桶的單詞绸贡,所以 “pope” 和 “pops “ 將匹配 ”pop_“盯蝴。每次我們找到一個(gè)匹配的桶,我們就把單詞放在那個(gè)桶听怕。同一個(gè)桶中只有一個(gè)字母不同捧挺,形成鄰接棋蚌。

from pythonds.graphs import Graph

def buildGraph(wordFile):
    d = {}
    g = Graph()
    wfile = open(wordFile,'r')
    # create buckets of words that differ by one letter
    for line in wfile:
        word = line[:-1]
        for i in range(len(word)):
            bucket = word[:i] + '_' + word[i+1:]
            if bucket in d:
                d[bucket].append(word)
            else:
                d[bucket] = [word]
    # add vertices and edges for words in the same bucket
    for bucket in d.keys():
        for word1 in d[bucket]:
            for word2 in d[bucket]:
                if word1 != word2:
                    g.addEdge(word1,word2)
    return g
其他

深度優(yōu)先
廣度優(yōu)先搜索
D算法
prim算法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末励背,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子捷泞,更是在濱河造成了極大的恐慌声搁,老刑警劉巖黑竞,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捕发,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡很魂,警方通過(guò)查閱死者的電腦和手機(jī)扎酷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)遏匆,“玉大人霞玄,你說(shuō)我怎么就攤上這事±辏” “怎么了坷剧?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)喊暖。 經(jīng)常有香客問(wèn)我惫企,道長(zhǎng),這世上最難降的妖魔是什么陵叽? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任狞尔,我火速辦了婚禮,結(jié)果婚禮上巩掺,老公的妹妹穿的比我還像新娘偏序。我一直安慰自己,他們只是感情好胖替,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布研儒。 她就那樣靜靜地躺著,像睡著了一般独令。 火紅的嫁衣襯著肌膚如雪端朵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天燃箭,我揣著相機(jī)與錄音冲呢,去河邊找鬼。 笑死招狸,一個(gè)胖子當(dāng)著我的面吹牛敬拓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播裙戏,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼乘凸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了挽懦?” 一聲冷哼從身側(cè)響起翰意,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎信柿,沒想到半個(gè)月后冀偶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡渔嚷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年进鸠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片形病。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡客年,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出漠吻,到底是詐尸還是另有隱情量瓜,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布途乃,位于F島的核電站绍傲,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏耍共。R本人自食惡果不足惜烫饼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望试读。 院中可真熱鬧杠纵,春花似錦、人聲如沸钩骇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)倘屹。三九已至韩容,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唐瀑,已是汗流浹背群凶。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哄辣,地道東北人请梢。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像力穗,于是被迫代替她去往敵國(guó)和親毅弧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

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

  • 1 序 2016年6月25日夜当窗,帝都够坐,天下著大雨,拖著行李箱和同學(xué)在校門口照了最后一張合照,搬離寢室打車去了提前租...
    RichardJieChen閱讀 5,078評(píng)論 0 12
  • 樹的概述 樹是一種非常常用的數(shù)據(jù)結(jié)構(gòu)元咙,樹與前面介紹的線性表梯影,棧,隊(duì)列等線性結(jié)構(gòu)不同庶香,樹是一種非線性結(jié)構(gòu) 1.樹的定...
    Jack921閱讀 4,442評(píng)論 1 31
  • 因?yàn)橹熬蛷?fù)習(xí)完數(shù)據(jù)結(jié)構(gòu)了甲棍,所以為了保持記憶,整理了一份復(fù)習(xí)綱要赶掖,復(fù)習(xí)的時(shí)候可以看著綱要想具體內(nèi)容感猛。 樹 樹的基本...
    牛富貴兒閱讀 6,828評(píng)論 3 10
  • 基于樹實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu),具有兩個(gè)核心特征: 邏輯結(jié)構(gòu):數(shù)據(jù)元素之間具有層次關(guān)系奢赂; 數(shù)據(jù)運(yùn)算:操作方法具有Log級(jí)的平...
    yhthu閱讀 4,254評(píng)論 1 5
  • 簡(jiǎn)單演練 階段性小結(jié)函數(shù)定義格式:func 函數(shù)名(參數(shù): 參數(shù)類型...) -> 返回值 { // 代碼實(shí)現(xiàn) }...
    展昭酷愛寫作閱讀 97評(píng)論 0 0