#Page111 队列 击鼓传花
from pythonds.basic.queue import Queue #import对应模块
def hotPotato(namelist, num):#参数为人队列和次数
simqueue = Queue()#创建新的队列
for name in namelist:#对于namelist中的每个元素
simqueue.enqueue(name)#把其压入此队列中
#压入所有姓名
while simqueue.size() > 1:#如果不到最后(因为最后要求只剩一个人)
for i in range(num):#
simqueue.enqueue(simqueue.dequeue())#把列头pop出来,再塞到队尾,重复num次
simqueue.dequeue()#每完成Num次,永久弹出列头,直到simqueue.size()=1
return simqueue.dequeue()#直到最终把剩下的那个人的名字展示出来
#page122 回文检查
from pythonds.basic.deque import Deque #import双端队列模块
def palchecker(aString):#输入是一串字符串
chardeque = Deque()#创建双端队列
for ch in aString:
chardeque.addRear(ch)#把输入的字符串每个字符依次添加到队尾
stillEqual = True
while chardeque.size() > 1 and stillEqual:#双闸控制的while语句
first = chardeque.removeFront()#弹出头部
last = chardeque.removeRear()#弹出尾部
if first != last:
stillEqual = False#不相等的话就直接跳出循环
return stillEqual#表示是否回文匹配完全成功
#时间复杂度为O(n)的两列表合并且排序算法
for k = 1 to n
if B(i)<C(i)
D(k)=B(i)
i++
else [C(j)<B(i)]
D(k)=C(j)
j++
End
#进制任意转化
def toStr(n,base):#参数是十进制数字,以及要转换到的进制
convertString = '0123456789ABCDEF'
if n < base:#如果此数小于要转换成的进制,那么就直接
return convertString[n]
else:
return toStr(n//base,base) + convertString[n%base]
#利用栈的特性进行进制转化
from pythonds.basic.stack import Stack#导入stack模块
rStack = Stack()
def toStr(n,base):
convertString = '0123456789ABCDEF'
while n > 0:#控制语句,当输入的数字大于0才有意义
if n < base:#如果n小于要转换成的进制
rStack.push(convertString[n])#就直接压入栈中
else:
rStack.push(convertString[n%base])#否则就压入余数
n = n//base #没压制一次余数之后,都要利用\\运算符,因为此循环总要有个控制结束的语句
res = ''#创建空字符串
while not rStack.isEmpty():#当此栈为非空时
res = res + str(rStack.pop())#依次弹出,这样即利用了栈的性质,因为第一个压入的实际上是结果的最后一位
return res
#可视化递归 turtle模块
import turtle
myTurtle = turtle.Turtle()
myWin = turtle.Screen()
def drawSpiral(myTurtle,lineLen):
if lineLen > 0:
myTurtle.forward(lineLen)
myTurtle.right(90)
drawSpiral(myTurtle,lineLen-5)#呈正方形螺旋湮灭,最后不满足条件了就停止
drawSpiral(myTurtle,100)
myWin.exitonclick()
import turtle
def tree(branchLen,t):#到达最深层再退回来,退回来,在执行左边,在退回来
if branchLen>5:
t.forward(branchLen)
t.right(20)
tree(branchLen-15,t)#执行第一个递归,即重复这个递归之上的语句,直到最底层(或者说最深层)
t.left(40)
tree(branchLen-15,t)#
t.right(20)
t.backward(branchLen)#从后面的执行过程可以看出,这种递归是先
def main():
t = turtle.Turtle()
myWin = turtle.Screen()
t.left(90)
t.up()
t.backward(100)
t.down()
t.color('green')
tree(75,t)
myWin.exitonclick()
main()
#汉诺塔
def moveTower(height,fromPole,toPole,withPole):
if height>=1:
moveTower(height-1,fromPole,withPole,toPole)
moveDisk(fromPole,toPole)
moveTower(height-1,withPole,toPole,fromPole)
def moveDisk(fp,tp):
print('moving disk from',fp,'to',tp)#虽然具体实现过程还是迷迷糊糊的,但是通过证明此代码完全没问题
moveTower(3,1,2,3)
#迷宫的设计与其蕴含的递归思想
#代码数量繁杂,因此暂时不写
#二分搜索 binary_search递归版本
def binary_search(arr,start,end,hkey):#四个参数 要搜寻的已经排过序的数列,数列的开始index和结束index,要搜寻的目标元素
if start > end:#如果此数列未经过排序,是不行的
return -1
mid = start + (end - start) / 2#如果通过了第一步,那么就找中点的index值
if arr[mid] > hkey:#如果index mid在数列arr中大于要搜寻的目标,证明在左半区
return binary_search(arr, start, mid - 1, hkey)#递归调用,将end改为mid-1
if arr[mid] < hkey:#如果大于,则是右半区
return binary_search(arr, mid + 1, end, hkey)
return mid#最后结果输出是mid值?这个二分搜索必须是连续的整数?还是说这段code的本意就是定位此元素所在的位置?
#二分查找的非递归版本
def binarySearch(alist,item):
first = 0
last = len(alist)-1
found = False
while first<=last and not found:#如果队列没结束而且也没有找到匹配,就执行以下
midpoint = (first+last)//2
if alist[midpoint] == item:
found = True
else:
if item < alist[midpoint]:#说明在右半段
last = midpoint-1#将结束搜索点前移
else:
first = midpoint+1#说明在左半段#将开始搜索点后移
return found
#硬币找零问题(目的是找出所需硬币总数最小的找零方案)
#初级code
def recMC(coinValueList,change):#相当于倒序查找,人脑想先比配最大的,比如25美分,但是程序用1美分开始,减去一美分,看看余下的是不是能被25,10,5整除,不能的话再减去一美分,再试,能的话就减去整除所消耗的结果。其实刚开始我们就要看能不能整除,不能的话在执行减一的迭代操作。
minCoins = change
if change in coinValueList:#如果是直接在里面,一个硬币就够了
return 1
else :
for i in [c for c in coinValueList if c<=change]:#如果至少需要的change多于一个,对coinValueList进行遍历
numCoins = 1 + recMC(coinValueList,change-i)
if numCoins < minCoins:#如果找零硬币的个数小于要找零的金额
minCoins = numCoins#先执行迭代,然后检查接下来的语句?迭代难道不是个无底洞吗,直到迭代到最基层,但是最基层的控制语句在哪里体现呢?
return minCoins
print(recMC[1,5,10,25],63)
#但是上述方法有些繁杂,所以不妨记住一些过去的结果,可以避免重新计算以前的结果:what's that supposed to mean?
def recDC(coinValueList,change,knownResults):
minCoins = change
if change in coinValueList:
knownResults[change]=1
return 1
elif knownResults[change]>0:#第一次试执行此语句的时候,是必然不满足的?
return knownResults[change]
else:
for i in [c for c in coinValueList if c<=change]:
numCoins = 1 + recDC(coinValueList,change-i,knownResults)
if numCoins < minCoins:
minCoins = numCoins
knownResults[change] = minCoins
return minCoins#真让人头大,看不懂
#更优的解,采用动态规划算法来解决找零问题:很明显,这个函数没有用到递归,所以递归虽好,有时候还是比不上迭代哦
def dpMakeChange(coinValueList,change,minCoins):#假设change=63
for cents in range(change+1):#cents的数额从0到63增加
coinCount = cents
for j in [c for c in coinValueList if c <=cents]:#当coinValueList中的值小于逐步增长的c时,这个cent=1234的时候只有1满足,cent=56789的时候有1和5满足
if minCoins[cents-j]+1 < coinCount:#minCoins到底是什么东西?
coinCount[cents] = minCoins[cents-j]+1
minCoins[cents] = coinCount
return minCoins[change]#返回从0到找零值的所有值的解
#双闸控制的while语句,很实用
pos = 0
found = False
while pos < len(alist) and not found:
if alist == item:
found = True
else:
pos = pos+1
#以上就是遍历搜索的两个控制条件:第一是搜索完全长,那么停止,要么是找到了所需的项目,那么也停止
#冒泡排序
def bubbleSort(alist):#按从小到大排列
for passnum in range(len(alist)-1,0,-1):#倒序输入alist长度的range
for i in range(passnum):#进行第一次遍历,长度为n-1,第二次为n-2...
if alist[i]>alist[i+1]:#如果前一项大于后一项
temp=alist[i]
alist[i]=alist[i+1]
alist[i+1]=temp #调换顺序
alist=[54,26,93,17,77,31,44,55,20]
bubbleSort(alist)
print(alist)#证明排序之后,改变了原列表顺序
#短冒泡排序
def shortBubbleSort(alist):
exchanges = True
passnum = len(alist)-1
while passnum > 0 and exchanges:
exchanges = False
for i in range(passnum):#第一次遍历,的确是n-1次
if alist[i]>alist[i+1]:#如果有需要交换的,如果这次遍历从头到尾不需要交换,那么exchanges这个变量就保持false状态。这次遍历不需要交换说明这次遍历中遍历的数据都已经排好,再加上后面已经排好的,整个list就完全排好了,直接结束while 语句,输出alist即可。
exchanges = True
temp=alist[i]
alist[i]=alist[i+1]
alist[i+1]=temp
passnum = passnum -1
alist = [17, 20, 26, 31, 44, 54, 55, 77, 93]
shortBubbleSort(alist)
print(alist)
#选择排序
def selectionSort(alist):
for fillslot in range(len(alist)-1,0,-1):
positionOfMax = 0#每次遍历开始前都要初始化一下
for location in range(1,fillslot+1):#遍历每一个位置,找到其中最大的,赋值给positionOfMax
if alist[location]>alist[positionOfMax]:
positionOfMax = location
temp = alist[fillslot]
alist[fillslot] = alist[positionOfMax]
alist[positionOfMax] = temp#每次遍历完一遍,就把这个最大值所对应的位置的元素跟index=fillslot的元素进行调换(注意,fillslot每遍历一遍都会减一)
alist=[54,26,93,17,77,31,44,55,20]
selectionSort(alist)
print(alist)
#插入排序
def insertSort(alist):
for index in range(1,len(alist)):#目前要被插入的队列只有最前面的那个元素,即Index=0
currentValue = alist[index]#依次取index=1,2....的值
position = index#初始化position至当前index
while position>0 and alist[position-1]>currentValue:#如果没到开头且前一个值大于当前值,(遍历前面已经排好序的列表,直到到开头或者找到一个合适的位置)
alist[position]=alist[position-1]#就把前一个值赋值给当前位置
position = position-1#将当前定位减一,即依次向前移
alist[position]=currentValue#把这个要插入的值排在前面已经拍好序列的position的位置
alist=[54,26,93,17,77,31,44,55,20]
insertSort(alist)
print(alist)
#希尔排序
def shellSort(alsit):
sublistcount = len(alist)//2
while sublistcount > 0 :
for startposition in range(sublistcount):
gapInsertionSort(alist,startposition,sublistcount)
print('After increment of size',sublistcount,'The list is',alist)
sublistcount = sublistcount//2
def gapInsertionSort(alist,start,gap):
for i in range(start+gap,len(alist),gap):
currentvalue = alist[i]
position = i
while position>=gap and alist[position-gap]>currentvalue:
alist[position]=alist[position-gap]
position = position-gap
alist[position]=currentvalue
alist=[54,26,93,17,77,31,44,55,20]
shellSort(alist)
print(alist)
#归并排序(Merge Sort Method)
def mergeSort(alist):
print('Splitting ',alist)
if len(alist)>1:
mid = len(alist)//2
lefthalf = alist[:mid]
righthalf = alist[mid:]#分裂的过程,分成左右半边
mergeSort(lefthalf)
mergeSort(righthalf)#执行递归的操作,将会一直分裂下去,直到成1
i=0
j=0
k=0
while i <len(lefthalf) and j <len(righthalf):#控制条件是i和j只要有一个遍历完成结束
if lefthalf[i] < righthalf[j]:#如果左边列第i个小于右边列第J个,就将较小的赋值给合并后排序集合,用完了这个i就i=i+1
alist[k] = lefthalf[i]
i = i+1
else:#右边j元素小,就赋值j,然后用完了这个j,就j=j+1
alist[k]=righthalf[j]
j = j+1
k =k+1
while i <len(lefthalf):#由于上一个控制语句最后返回要么是i已经最大,或者j已经到达最大,所以这个和下一个控制语句都是做结尾的工作(因为lefthalf和righthalf 都是已经排好序的,所以谁要是被剩下了,就把剩下的元素直接添加到alist结尾即可
alist[k]=lefthalf[i]
i=i+1
k=k+1
while j<len(righthalf):
alist[k]=righthalf[j]
j=j+1
k=k+1
print('Merging ',alist)
alist=[54,26,93,17,77,31,44,55,20]
mergeSort(alist)
print(alist)#由最后输出的结果可以很好的得出各语句执行的顺序
#快速排序
def quickSort(alist):#只接受一个参数,但是接下来把要用到的其他二级参数都转化了出来,就不用用户手动输入这些数据了
quickSortHelper(alist,0,len(alist)-1)
def quickSortHelper(alist,first,last):#这个函数的用意是每次在splitpoint处将alist递归分割
if first<last:
splitpoint = partition(alist,first,last)#splitpoint计算过程,这个partition函数返回pivot插入点所在的index,作为分裂点
quickSortHelper(alist,first,splitpoint-1)
quickSortHelper(alist,splitpoint+1,last)
def partition(alist,first,last):
pivotvalue = alist[first]#由于最开始是零,因此第一个选取的pivot点是第一个元素
leftmark = first + 1#左指针定在了povit后面
rightmark = last#last值为len(alist)-1,即最后一个元素的index号
done = False
while not done:
while leftmark<=rightmark and alist[leftmark]<=pivotvalue:#如果左指针对应的这个数小于枢纽数,那么就位置不变,指针向下一位移动(向右移)否则就进行不下去。最终的状态是直到移到不能移,即需要swap的位置
leftmark = leftmark +1
while alist[rightmark]>=pivotvalue and rightmark>=leftmark:#如果右指针对应的这个数大于枢纽数,位置不变,指针向下一位移动(向左移)
rightmark = rightmark-1
if rightmark<leftmark:#说明全长不需要排列就好了或者经过swap后全长都排列好了
done = True#结束while not done 循环
else:#这个是一般情况,就swap一下
temp = alist[leftmark]
alist[leftmark] = alist[rightmark]
alist[rightmark] = temp
temp = alist[first]#把rightmark对应的元素和pivot置换一下,即把pivot换到合适的位置
alist[first] = alist[rightmark]
alist[rightmark] = temp
return rightmark#每次使用此partition函数都相当于遍历了一遍然后返回rightmark的index
alist=[54,26,93,17,77,31,44,55,20]
quickSort(alist)
print(alist)
#树的结构
myTree = ['a',['b',['d',[],[]],['e',[],[]],['c',['f',[],[]],[]]]]
print(myTree)
print('left subtree = ',myTree[1])
print('root=',myTree[0])
print('right subtree =',myTree[2])
def BinaryTree(r):
return [r,[],[]]#简单的构造一个具有根节点和两个子列表为空的列表
#插入左子节点
def insertLeft(root,newBranch):
t= root.pop(1)#树就像是一个栈,弹出root第二个元素,左子节点
if len(t) > 1:#如果内容长度大于1
root.insert(1,[newBranch,t,[]])
else:
root.insert(1,[newBranch,[],[]])
return root#注意,要插入一个左子节点,我们首先获得与当前左子节点对应的列表。然后我们添加新的左子树,添加旧的左子树作为新子节点的左子节点
#插入右子节点
def insertRight(root,newBranch):
t= root.pop(2)#树就像是一个栈,弹出root第三个元素,右子节点
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]
##################以上是列表表示树的结构###############################
##################以下是节点表示树的结构###############################
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
r = BinaryTree('a')
print(r.getRootVal())
print(r.getLeftChild())
#利用栈和双叉树,创建四则运算分析树
from pythonds.basic.stack import Stack
from pythonds.trees.binaryTree import BinaryTree#导入Stack和BinaryTree模块
def buildParseTree(fpexp):#参数是正常的数学表达式
fplist = fpexp.split()
pStack = Stack()
eTree = BinaryTree('')#创建空的二叉树
pStack.push(eTree)#把此二叉树推到栈中
currentTree = eTree
for i in fplist:#下面是四则运算的实现过程
if i == '(':
currentTree.insertLeft('')#插入空的左子节点
pStack.push(currentTree)#推到栈中
currentTree = currentTree.getLeftChild()#把指针移到左子节点上
elif i not in ['+','-','*','/',')']:#如果i是操作数
currentTree.setRootVal(i)#那么就将这个操作数作为一个object,写入当前节点
currentTree.insertRight('')#并且插入父节点的右节点
pStack.push(currentTree)#将完成这些操作 的currentTree压入栈中
currentTree = currentTree.getRightChild()#指针指到右子节点
elif i == ')':#如果是此操作符
currentTree = pStack.pop()#将pstack弹出,返回到current里面,使得当前节点返回父节点
else:
raise ValueError
return eTree#返回etree
pt = buildParseTree('((10+5)*3)')
#pt.postorder()
def evaluate(parseTree):#对树所进行的递归算法基本情况是检查叶节点
opers = {'+':operator.add,'-':operator.sub,'*':operator.mul,'/':operator.truediv}
leftC = parseTree.getLeftChild()
rightC = parseTree.getRightChild()
if leftC and rightC:
fn = opers[parseTree.getRootVal()]
return fn(evaluate(leftC),evaluate(rightC))
else:
return parseTree.getRootVal()
#遍历树结构方法一 前序遍历
def preorder(tree):#(这种方式更好)
if tree:#基本情况只是检查树是否存在
print(tree.getRootVal())
preorder(tree.getLeftChild())
preorder(tree.getRightChild())
#或者把preorder作为BinaryTree类的一个方法
def preorder(self):
print(self.key)
if self.leftChild:
self.leftChild.preorder()
if self.rightChild:
self.rightChild.preorder()
#遍历数结构方法二 后序遍历
def preorder(tree):#(这种方式更好)
if tree != None:#基本情况只是检查树是否存在
preorder(tree.getLeftChild())
preorder(tree.getRightChild())
print(tree.getRootVal())
def postordereval(tree):#后序遍历实例
opers = {'+':operator.add,'-':operator.sub,'*':operator.mul,'/':operator.truediv}
res1 = None
res2 = None
if tree:
res1 = postordereval(tree.getLeftChild())
res2 = postordereval(tree.getRightChild())#先获取左右节点
if res1 and res2:
return opers[tree.getRootVal()](res1,res2)#最后通过操作符的函数调用在根节点中组合他们
else:
return tree.getRootVal()
#遍历数结构方法三 中序遍历
def preorder(tree):#(这种方式更好)
if tree != None:#基本情况只是检查树是否存在
preorder(tree.getLeftChild())
print(tree.getRootVal())
preorder(tree.getRightChild())
def printexp(tree):#实例,恢复表达式
sVal = ''
if tree:
sVal = '(' + printexp(tree.getLeftChild())#获取左子树
sVal = sVal + str(tree.getRootVal())#获取根节点
sVal = sVal + printexp(tree.getRightChild())+')'#再获取右子树
return sVal
#实现二叉树的最小堆结构
from pythonds.trees.binheap import BinHeap
bh = BinHeap()
bh.insert(5)
bh.insert(7)
bh.insert(3)
bh.insert(11)
print(bh.delMin())
print(bh.delMin())
print(bh.delMin())
print(bh.delMin())
#二叉堆类的定义
class BinHeap:
def __init__(self):
self.heapList = [0]#这个零放在这里为了之后简单的整数除法
self.currentSize = 0
def percUp(self,i):
while i//2 >0:#也就是说,i不取0不取1都可以,即向上swap 到最顶层为止
if self.heapList[i] < self.heapList[i//2]:#子节点小于父节点
tem = self.heapList[i//2]#将执行swap 操作
self.heapList[i//2] = self.heapList[i]
self.heapList[i] = tmp
i = i//2#子节点大于父节点,就不执行任何操作
def insert(self,k):
self.heapList.append(k)
self.currentSize = self.currentSize + 1
self.percUp(self.currentSize)#我们写Insert函数的时候当然是先写insert,困难的部分由辅助函数处理,但是运行的时候辅助函数要先表示出来
def percDown(self,i):#i 是父节点,i*2是其子节点 本函数确保最大的子节点总是沿着树向下移动
while (i*2)<= self.currentSize:
mc = self.minChild(i)#minChild返回最小的节点的那个Index
if self.heapList[i] > self.heapList[mc]:#若父节点大于子节点,那么就交换
tmp = self.heapList[i]#将执行swap 操作
self.heapList[i] = self.heapList[mc]
self.heapList[mc] = tmp
i = mc
def minChild(self,i):
if i*2 +1 >self.currentSize:#如果子节点编号超出了树的大小,说明不存在
return i*2#返回左节点
else:
if self.heapList[i*2]<self.heapList[i*2+1]:#如果左节点小于右节点,返回左节点
return i*2
else:#否则返回右节点
return i*2+1
def delMin(self):
retval = self.heapList[1]
self.heapList[1] = self.heapList[self.currentSize]
self.currentSize = self.currentSize -1
self.heapList.pop()
self.percDown(1)
return retval
def buildHeap(self,alist):#从键列表构建一个新的堆
i = len(alist)//2
self.currentSize = len(alist)
self.heapList = [0] + alist[:]
while (i>0):
self.percDown(i)
i = i-1 #都不带返回值的?什么意思?
bh = BinHeap()
bh.buildHeap([9,5,6,2,3])#直接利用添加列表构建一个最小堆二叉树
print(bh.delMin())#先被删除的是2
print(bh.delMin())#再被删除的是3
#二叉搜索树
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#返回boolean
def isLeaf(self):
return not (self.rightChild or self.leftChild)#返回boolean
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
class BinarySearchTree:
def __init__(self):
self.root = None
self.size = 0
def length(self):
return self.size
def __len__(self):
return self.size
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,value,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)
def __setitem__(self,k,v):
self.put(k,v)
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)
def __iter__(self):
return self.root.__iter__()
#################y有时间再补全####################
#邻接表的实现
class Vertex:#Vertex Shell
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):#看connect到的另外几个节点是什么
return self.connectedTo.keys()
def getId(self):#获取有无此id的key
return self.id
def getWeight(self,nbr):#获取目标的权重
return self.connectedTo[nbr]
class Graph:#graph类实现了添加顶点,获取节点,添加边,in方法,遍历的magic method
def __init__(self):
self.vertList = {}
self.numVertices = 0
def addVertex(self,key):
self.numVertices = self.numVertices + 1
newVerex = Vertex(key)
self.vertList[key] = newVerex
return newVerex
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())
g = Graph()
for i in range(6):
g.addVertex(i)
print(g.vertList)
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()))
#字梯问题 构建图
from pythonds.graphs import Graph
def buildGraph(wordFile):
d = {}
g = Graph()
wfile = open(wordFile,'r')#以读取方式打开文件
for line in wfile:
word = line[:-1]
for i in range(len(word)):#创建buckets of words that differ by one letter
bucket = word[:i]+'-'+word[i+1:]#对每个位置都创建一个空格
if bucket in d:
d[bucket].append(word)#把初始的附在每个桶里
else:
d[bucket] = [word]
for bucket in d.keys():#add vertices and edges for words in the same bucket
for word1 in d.keys():
for word2 in d[bucket]:
if word1 != word2:
g.addEdge(word1,word2)
return g
#现在我们可以把注意力转向最短解
from pythonds.graphs import Graph,Vertex
from pythonds.basic import Queue
def bfs(g,start):
start.setDistance(0)
start.setPred(None)
vertQueue = Queue()
vertQueue.enqueue(start)
while (vertQueue.size()>0):
currentVert = vertQueue.dequeue()
for nbr in currentVert.getConnections():
if (nbr.getColor()=='white'):
nbr.setColor('gray')
nbr.setDistance(currentVert.getDistance()+1)
nbr.setPred(currentVert)
vertQueue.enqueue(nbr)
currentVert.setColor('black')
#骑士之旅 深度优先搜索
from pythonds.graphs import Graph
def knightGraph(bdSize):#在整个板上进行一次遍历
ktGraph = Graph()
for row in range(bdSize):
nodeId = posToNodeId(row,col,bdSize)
newPositions = genLegalMoves(row,col,bdSize)#为板上的位置创建一个移动列表,所有的移动在图形中转化为边
for e in newPositions:
nid = posToNodeId(e[0],e[1],bdSize)
ktGraph.addEdge(nodeId,nid)
return ktGraph
def posToNodeId(row,column,board_size):#把位置转化成node ID
return (row*board_size)+column
def genLegalMoves(x,y,bdSize):#利用当前骑士的位置 生成八个合法的可能的移动中的一个
newMoves =[]
moveOffsets = [(-1,-2),(-1,2),(-2,-1),(-2,1),(1,-2),(1,2),(2,-1),(2,1)]
for i in moveOffsets:#遍历所有可能移动
newX = x + i[0]
newY = y + i[1]
if legalCoord(newX,bdSize) and legalCoord(newY,bdSize):
newMoves.append((newX,newY))
return newMoves
def legalCoord(x,bdSize):#
if x>=0 and x< bdSize:#如果还在棋盘范围内,那么就是可以继续操作
return True
else:#否则不行
return False
#深度优先搜索算法一 解决骑士问题
from pythonds.graphs import Graph,Vertex
def knightTour(n,path,u,limit):#四个参数,n表示树中的当前深度。path,表示到此为止访问过的顶点的列表 u,图中希望探索的顶点。limit 路径中的节点数 这个函数是递归的
u.setColor('gray')#未访问的节点是白色的,访问过是灰色的
path.append(u)
if n < limit:
nbrList = list(u.getConnections())
i = 0
done = False
while i<len(nbrList) and not done:
if nbrList[i].getColor()=='white':
done = knightTour(n+1,path,nbrList[i],limit)
i = i+1
if not done:
path.pop()
u.setColor('white')
else:#如果返回一个正好包含所有节点的路径,就说明成功了
done = True
return done
#最短加权路径的Dijkstra算法
from pythonds.graphs import PriorityQueue, Graph, Vertex
def dijkstra(aGraph, start):#参数是图 和 给定的开始节点
pq = PriorityQueue()#优先级队列(这种类储存键值对的元组,值用于确定优先级即确定键在队列中的位置,键是顶点。在这个算法中,我们使用到顶点的距离作为优先级,因为探索下一个顶点总要探索距离最近的顶点
start.setDistance(0)
pq.buildHeap([v.getDistance(),v] for v in aGraph)
while not pq.isEmpty():
currentVert= pq.delMin()
for nextVert in currentVert.getConnections():
newDist = currentVert.getDistance() + currentVert.getWeight(nextVert)
if newDist < nextVert.getDistance():
nextVert.setDistance(newDist)
nextVert.setPred(currentVert)
pq.decreaseKey(nextVert, newDist)#使用优先级队列类中的decreaseKey方法
#贪心算法のprim算法:
from pythonds.graphs import PriorityQueue, Graph, Vertex
def prim(G,start):
pq = PriorityQueue()
for v in G:
v.setDistance(sys.maxsize)
v.setPred(None)
start.setDistance(0)
pq.buildHeap([v.getDistance(),v] for v in G)
while not pq.isEmpty():
currentVert = pq.delMin()
for nextVert in currentVert.getConnections():
newCost = currentVert.getWeight(nextVert)
if nextVert in pq and newCost<nextVert.getDistance():
nextVert.setPred(currentVert)
nextVert.setDistance(newCost)
pq.decreaseKey(nextVert,newCost)