哎,好久没写博文了,其实仔细想来,时间还是蛮多的,以后还是多写写吧!
之前看过经典的搜索路径方法,印象较深的也就BFS(广度优先),DFS(深度优先)以及A*搜索,但没实践过,就借八数码问题,来通通实现遍,观察下现象呗~~~
首先,怎么说也得把数码这玩意基本操作实现了呗!上代码~
class puzzled:
def __init__(self,puzzled):
self.puzzled=puzzled
self.__getPuzzledInfo()
def __getPuzzledInfo(self):
self.puzzledWid=len(self.puzzled[0])
self.puzzledHei=len(self.puzzled)
self.__f1=False
for i in range(0,self.puzzledHei):
for j in range(0,self.puzzledWid):
if(self.puzzled[i][j]==0):
self.zeroX=j
self.zeroY=i
self.__f1=True
break
if(self.__f1):
break
def printPuzzled(self):
for i in range(0,len(self.puzzled)):
print self.puzzled[i]
print ""
def isRight(self):
if(self.puzzled[self.puzzledHei-1][self.puzzledWid-1]!=0):
return False
for i in range(0,self.puzzledHei):
for j in range(0,self.puzzledWid):
if(i*self.puzzledWid+j+1!=self.puzzled[i][j]):
if(i!=self.puzzledHei-1 or j!=self.puzzledWid-1):
return False
return True
def move(self,dere):#0 up,1 down,2 left,3 right
if(dere==0 and self.zeroY!=0):
self.puzzled[self.zeroY-1][self.zeroX],self.puzzled[self.zeroY][self.zeroX] = self.puzzled[self.zeroY][self.zeroX],self.puzzled[self.zeroY-1][self.zeroX]
self.zeroY-=1
return True
elif(dere==1 and self.zeroY!=self.puzzledHei-1):
self.puzzled[self.zeroY+1][self.zeroX],self.puzzled[self.zeroY][self.zeroX] = self.puzzled[self.zeroY][self.zeroX],self.puzzled[self.zeroY+1][self.zeroX]
self.zeroY+=1
return True
elif(dere==2 and self.zeroX!=0):
self.puzzled[self.zeroY][self.zeroX-1],self.puzzled[self.zeroY][self.zeroX] = self.puzzled[self.zeroY][self.zeroX],self.puzzled[self.zeroY][self.zeroX-1]
self.zeroX-=1
return True
elif(dere==3 and self.zeroX!=self.puzzledWid-1):
self.puzzled[self.zeroY][self.zeroX+1],self.puzzled[self.zeroY][self.zeroX] = self.puzzled[self.zeroY][self.zeroX],self.puzzled[self.zeroY][self.zeroX+1]
self.zeroX+=1
return True
return False
def getAbleMove(self):
a=[]
if(self.zeroY!=0):
a.append(0)
if(self.zeroY!=self.puzzledHei-1):
a.append(1)
if(self.zeroX!=0):
a.append(2)
if(self.zeroX!=self.puzzledWid-1):
a.append(3)
return a
def clone(self):
a=copy.deepcopy(self.puzzled)
return puzzled(a)
def toString(self):
a=""
for i in range(0,self.puzzledHei):
for j in range(0,self.puzzledWid):
a+=str(self.puzzled[i][j])
return a
def isEqual(self,p):
if(self.puzzled==p.puzzled):
return True
return False
def toOneDimen(self):
a=[]
for i in range(0,self.puzzledHei):
for j in range(0,self.puzzledWid):
a.append(self.puzzled[i][j])
return a
def getNotInPosNum(self):
t=0
for i in range(0,self.puzzledHei):
for j in range(0,self.puzzledWid):
if(self.puzzled[i][j]!=i*self.puzzledWid+j+1):
if(i==self.puzzledHei-1 and j==self.puzzledWid-1 and self.puzzled[i][j]==0):
continue
t+=1
return t
def getNotInPosDis(self):
t=0
it=0
jt=0
for i in range(0,self.puzzledHei):
for j in range(0,self.puzzledWid):
if(self.puzzled[i][j]!=0):
it=(self.puzzled[i][j]-1)/self.puzzledWid
jt=(self.puzzled[i][j]-1)%self.puzzledWid
else:
it=self.puzzledHei-1
jt=self.puzzledWid-1
t+=abs(it-i)+abs(jt-j)
return t
@staticmethod
def generateRandomPuzzle(m,n,ran):
tt=[]
for i in range(0,m):
t=[]
for j in range(0,n):
t.append(j+1+i*n)
tt.append(t)
tt[m-1][n-1]=0
a=puzzled(tt)
i=0
while(i
稍微注解一下,puzzled类表示一个数码类,初始化利用
a=puzzled( [1,2,3],
[4,5,6],
[7,8,0])
其中呢,0表示空格位置,上面初始化的便是一个正确的,未被打乱的位置~
其他的成员函数,看名称就很好理解了呗~
ok,基础打好了,接下来就该上节点类了:
class node:
def __init__(self,p):
self.puzzled=p
self.childList=[]
self.father=None
def addChild(self,child):
self.childList.append(child)
child.setFather(self)
def getChildList(self):
return self.childList
def setFather(self,fa):
self.father=fa
def displayToRootNode(self):
t=self
tt=0
while(True):
tt+=1
t.puzzled.printPuzzled()
t=t.father
if(t==None):
break
print "it need "+str(tt)+ " steps!"
def getFn(self):
fn=self.getGn()+self.getHn() #A*
#fn=self.getHn() #贪婪
return fn
def getHn(self):
Hn=self.puzzled.getNotInPosDis()
return Hn
def getGn(self):
gn=0
t=self.father
while(t!=None):
gn+=1
t=t.father
return gn
对于节点类吧,也还是很好理解的,初始化方法
a=node(
puzzled([1,2,3],
[4,5,6],
[7,8,0])
)
基础都搭好了,重点人物该闪亮登场了呗~
class seartchTree:
def __init__(self,root):
self.root=root
def __search2(self,hlist,m): #二分查找,经典算法,从大到小,返回位置
#若未查找到,则返回应该插入的位置
low = 0
high = len(hlist) - 1
mid=-1
while(low <= high):
mid = (low + high)/2
midval = hlist[mid]
if midval > m:
low = mid + 1
elif midval < m:
high = mid - 1
else:
return (True,mid)
return (False,mid)
def __sortInsert(self,hlist,m):#对于一个从大到小的序列,
#插入一个数,仍保持从大到小
t=self.__search2(hlist,m)
if(t[1]==-1):
hlist.append(m)
return 0
if(m
注意到里面存在一个 NumTree,这个是个啥玩意了,这个吧,其实是一个closed表,啥是Closed表呢?
就是呀,在搜索的时候,得记录已经扩展的节点,不然的话很有可能成为不完备的搜索了(对于深度搜索),而且已经扩展的状态,也对于数码问题没必要在扩展一次,那么怎么来实现记录已经扩展的节点呢?
一个最简单的方法就是建立一个链表,将扩展的节点加进去,但这样存在一个问题,就是由于每次在扩展节点时都得遍历closed表,查找是否存在同样的节点已经被扩展,这样,复杂度就简直太高了,完全不行呗~
那么咋办呢?从上面代码注意到,node对象里面有一个Puzzled成员,实际上puzzled对象主要就由一个二维数组构成呗~这时候呀,我就把这个二维数组变为一维呗
[1,2,3],
[4,5,6], -> [1,2,3,4,5,6,7,8,0]
[7,8,0]
然后呢,利用trie树存储该数组,这样一来,查找添加一步到位!
也就是上面代码中的这个啦~
numTree.searchAndInsert(a.puzzled.toOneDimen())
贴上numtree代码:
class NumTree:
def __init__(self):
self.root = Node()
def insert(self, key): # key is of type string
# key should be a low-case string, this must be checked here!
node = self.root
for char in key:
if char not in node.children:
child = Node()
node.children[char] = child
node = child
else:
node = node.children[char]
node.value = key
def search(self, key):
node = self.root
for char in key:
if char not in node.children:
return None
else:
node = node.children[char]
return node.value
def display_node(self, node):
if (node.value != None):
print node.value
for char in node.children.keys():
if char in node.children:
self.display_node(node.children[char])
return
def display(self):
self.display_node(self.root)
def searchAndInsert(self,m):
if(self.search(m)==None):
self.insert(m)
return False
return True
"""test
trie = NumTree()
print trie.searchAndInsert([1,2,3,4,5,6,7,8])
print trie.searchAndInsert([1,2,3,4,5,6,7,8,9])
trie.display()
"""
好了,这样再看searchTree的代码就比较清晰了呗,
哎,好吧,我承认这等低劣之作也只有我等渣渣才能写出,其实再看时,可以发现很多地方都可以优化的,比如二维转一维,这个其实花费的不少时间,其实可以在内部以一维形式存在的~
本文出自 “Rainlee的随笔记” 博客,请务必保留此出处http://rainlee.blog.51cto.com/7389753/1758071