python 实现树结构
简述:
研究 MCTS 过程中, 需要用到树结构。 baidu google 了一番, 找不到自己能满足自己的库或代码参考,只好再造个轮子出来
我造的树用来下五子棋 和 围棋用的, 有其它不同的应用场合, 那就需要在此基础上改造了。
本树的特点:
1. 支持多子节点 ( 网络上很多代码都是二叉树,不符合我的需求 )
2. 支持树的存储 和 读取, 网上很少看到。
正文:
下面按照 应用场景, 数据结构和接口 , 代码, 三个部分 自上向下说明。
应用场景:
一: 画一个根节点, 再加三个叶子的树 (参考 Tree.demo1())
data = ['{}'.format( random.random() * 10000 )]
self.addSubNodeToCur_Data( data ) self.moveUp();
data = ['{}'.format( random.random() * 10000 )]
self.addSubNodeToCur_Data( data ) self.moveUp();
data = ['{}'.format( random.random() * 10000 )]
self.addSubNodeToCur_Data( data ) self.save()
初始化出来的树,只有一个根节点 tree = Tree()
然后在根下面,加一个节点, 内容是 data ,必须是 list 结构, list 里的元素只能是 字符,数字, True/False , 不允许 object , list , ()
moveUp 是当前节点往上移动一层, 如果已经是根节点了,会返回False
addSubNodeToCur_Data(self, data, NodeId = 0, isMoveToSub = True ) 在当前节点下,增加一个节点,节点内容是 Data ; isMoveToSub 当前节点移到新增节点
NodeId 一般不需要设置, 如果你的树结构是清楚的时候, 知道NodeId 的情况下设置。
二: 保存树,读取树
self.load(self, filename = None) , load 之后 ,生成树
self.save(self, filename = None)
默认文件名 ./data.npy 可指定文件名 , .npy 结尾
三:生成棋谱树
该棋局, 只有 4个 落子点 , [(0, 0), (0, 1), (1, 0), (1, 1)] , 一个人下
根据数理分析, 会形成这样一棵树:
0 root_node 根节点
1 4 × node 第一步 节点数
2 3 x 4 x node 第二步节点数
3 2x 3x4xnode 第三步节点数
4 1x 2x3x4xnode 第四步节点数
下一局,形成的一个棋谱
# 下一局, 随机选一个点, 下满棋盘
def WzOne( tree ):
tree.reset() #让树当前节点回到根节点
avilAction = [(0, 0), (0, 1), (1, 0), (1, 1)] # 4个落子点
while( len(avilAction) >0 ): #无落子点
action = random.choice(avilAction) #随机一个落子点
avilAction.remove(action) data = list( action )
# 遍历当前前节点的子节点, 如果已经存在该落子点, 则跳到子节点
# 如果当前节点的子节点, 无该落子点, 则增加一个子节点
isExist = False
for node in tree.cur_Node.children :
if( node.getData() == data ):
isExist = True
tree.moveToNode_byNode( node )
break
if( isExist == False ):
tree.addSubNodeToCur_Data(data) pass
下100局,形成100局的棋谱
# 下100局, 拓展棋谱
def testWzTree():
'''
生成 落子树
'''
tree = Tree()
for i in range(100):
WzOne( tree ) tree.printTree()
tree.save() #读取树
print '------------------------------------------------'
tree2 = Tree()
tree2.load()
tree2.printTree()
pass
最多生成 24 个叶子(最低层)的树; 也就是 24个棋谱
三:生成10x10 的五子 对弈 棋谱树
理论最大棋谱数 100 x 98 x 96x 94 x ...... (不考虑五子成线) 貌似好几百亿
试验了一下 7 x7 对弈五子棋, 10000 局, 形成 195719 个节点的树
github :
https://github.com/rehylas/play_chess/blob/master/standTree/wuzi.py
待补充
数据结构和接口
本代码输出两个类:Node 和 Tree
节点保存的信息有两部分:
nodeInfo = [ nodeid, level, parentNodeid, [ node1,node2,node3 ] ]
data = [data1, data2,data3,data3 ] 随应用定义
Node 输出接口:
create
setData(Data)
setParent(Node)
addSubNode(Node)
getSubNodeList()
Tree 输出接口:
def __init__(self):
def reset(self):
def load(self, filename = None ):
def save(self, filename = None ):
def printTree(self):
def getRootNode(self):
def getCurNode(self):
def addSubNodeToCur_Node(self, subNode, isMoveToSub = True ):
def addSubNodeToCur_Data(self, data, NodeId = 0, isMoveToSub = True ):
def moveToNode(self,nodeId ):
def moveToNode_byNode(self, node ):
def serachNodeId(self, thisNode, nodeId):
def moveUp(self):
代码:
gitHub: https://github.com/rehylas/play_chess/blob/master/standTree/Tree.py
代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: hylas zhang import numpy as np;
import random ''' Node class data
data: []
nodeinfo: id, level, parentId, childrenIdList [ 0, 0, 0, [] ]
childrenIdList save to file : [1,2,3,4] ==> 1,2,3,4 export function:
create
setData(Data)
setParent(Node)
addSubNode(Node)
getSubNodeList() in function: ''' class Node():
def __init__(self, info=None, data=None, infodata = None ):
if( infodata != None ):
info = infodata[0:3] +[[]]
data = infodata[3:]
self.info = info
self.data = data
pass self.data = [''] #[ 0,0, '' ] #times, wins, values
if( data != None ):
self.data = data
self.nodeInfo=[ 0, 0 ,0, [] ] #Nodeid, level , parentId, childrenIdList
if( info != None ):
self.nodeInfo = info self.parent = None
self.children = []
pass def setData(self,data):
self.data = data def setParent(self, parentNode):
self.parent = parentNode def addChild(self, childNode ):
self.children += [ childNode ] def getSubNodeList(self):
return self.children def getDataInfo(self):
dataList = [self.nodeInfo[0],self.nodeInfo[1],self.nodeInfo[2]] +self.data
return dataList def getData(self):
return self.data def getInfo(self):
return self.nodeInfo def __repr__(self):
return "nodeInfo: {}, ".format(self.nodeInfo ) def __eq__(self, other):
selfVal = "{}".format(self.nodeInfo )
otherVal = "{}".format(other.nodeInfo) if hash(selfVal) == hash(otherVal):
return True
return False '''
Tree
export function:
1.create
2.getRootNode
3.getCurNode
4.reset( 一般 回溯之后 )
5.loadFile
6.saveFile
7.addNewNodeInCurNode 7.获取usb最优节点
8.增加新节点
9.移动当前节点 内部: ''' class Tree():
###### 输出
def __init__(self):
self.root_Node = Node()
self.cur_Node = self.root_Node
self.NodeCount = 1 # 节点+ 叶子数 + 1
pass def reset(self):
self.cur_Node = self.root_Node
pass def load(self, filename = None ):
if( filename == None ):
filename = './data.npy'
npData2 = np.load( filename )
lst2 = npData2.tolist()
for node in lst2:
info = node[0:3]
data = node[3:]
if( info[0] == 0 ):
continue
print 'want to add:'
print node if( info[2] == self.cur_Node.nodeInfo[0] ):
self.addSubNodeToCur_Data(data, NodeId = info[0] )
continue #self.cur_Node
count = 10
while( info[2] != self.cur_Node.nodeInfo[0] ) : ret = self.moveUp() if( ret == False ):
print 'error ......'
return continue self.addSubNodeToCur_Data(data, NodeId = info[0]) self.printTree()
pass def save(self, filename = None ):
if (filename == None):
filename = './data.npy' nodeLst = self.fetchAllNode()
dataList =[]
for node in nodeLst :
print node
dataList += [ node.getDataInfo() ]
# Node.
pass npData = np.array( dataList )
np.save(filename, npData ) '''
npData2 = np.load( './data.npy' )
lst2 = npData2.tolist()
print 'lst2:', lst2
''' def printTree(self):
nodeLst = self.fetchAllNode()
for node in nodeLst :
print node.getDataInfo()
pass def getRootNode(self):
return self.root_Node; def getCurNode(self):
return self.cur_Node; # nodeinfo: id, level, parentId, childrenIdList[0, 0, 0, []]
def addSubNodeToCur_Node(self, subNode, isMoveToSub = True ):
newNodeId = self.NodeCount
self.NodeCount += 1
self.cur_Node.children += [subNode]
self.cur_Node.nodeInfo[3] += [ newNodeId ] subNode.parent = self.cur_Node
subNode.nodeinfo[0] = newNodeId
subNode.nodeinfo[1] = self.cur_Node.nodeInfo[1] +1
subNode.nodeinfo[2] = self.cur_Node.nodeInfo[0]
subNode.nodeinfo[3] = []
if( isMoveToSub ):
self.cur_Node = subNode pass def addSubNodeToCur_Data(self, data, NodeId = 0, isMoveToSub = True ):
subNode = Node(data=data) if(NodeId == 0 ):
newNodeId = self.NodeCount
else:
newNodeId = NodeId
self.NodeCount += 1
self.cur_Node.children += [subNode]
self.cur_Node.nodeInfo[3] += [ newNodeId ] subNode.parent = self.cur_Node subNode.nodeInfo[0] = newNodeId
subNode.nodeInfo[1] = self.cur_Node.nodeInfo[1] +1
subNode.nodeInfo[2] = self.cur_Node.nodeInfo[0]
subNode.nodeInfo[3] = []
#print 'addSubNodeToCur_Data, now in :', self.cur_Node.nodeInfo[0]
if( isMoveToSub ):
self.cur_Node = subNode #print 'addSubNodeToCur_Data, now in :', self.cur_Node.nodeInfo[0] def moveToNode(self,nodeId ):
node = self.serachNodeId( self.root_Node, nodeId)
if (node!= None):
self.cur_Node = node
return node
else:
return None
pass def moveToNode_byNode(self, node ):
self.cur_Node = node
pass def fetchAllNode(self):
return self.touchAllNode( self.getRootNode() )
pass # in function
def touchAllNode(self, thisNode):
allNode = [ thisNode ]
for node in thisNode.children :
allNode += self.touchAllNode( node ) return allNode def serachNodeId(self, thisNode, nodeId):
if( thisNode.nodeInfo[0] == nodeId ):
return thisNode
else:
for node in thisNode.children :
ret = self.serachNodeId(node , nodeId )
if( ret != None ):
return ret return None ###### 内部函数
def moveUp(self):
if( self.cur_Node.nodeInfo[0] == 0 ):
print 'moveUp error'
return False self.cur_Node = self.cur_Node.parent;
return True ######## test
def demo1(self):
data = ['{}'.format( random.random() * 10000 )]
self.addSubNodeToCur_Data( data ) self.moveUp();
data = ['{}'.format( random.random() * 10000 )]
self.addSubNodeToCur_Data( data ) self.save()
pass def deom2(self):
self.load() # 下100局, 拓展棋谱
def testWzTree():
'''
生成 落子树
'''
tree = Tree()
for i in range(100):
WzOne( tree ) tree.printTree()
tree.save() #读取树
print '------------------------------------------------'
tree2 = Tree()
tree2.load()
tree2.printTree()
pass # 下一局, 随机选一个点, 下满棋盘
def WzOne( tree ):
tree.reset() #让树当前节点回到根节点
avilAction = [(0, 0), (0, 1), (1, 0), (1, 1)] # 4个落子点
while( len(avilAction) >0 ): #无落子点
action = random.choice(avilAction) #随机一个落子点
avilAction.remove(action) data = list( action )
# 遍历当前前节点的子节点, 如果已经存在该落子点, 则跳到子节点
# 如果当前节点的子节点, 无该落子点, 则增加一个子节点
isExist = False
for node in tree.cur_Node.children :
if( node.getData() == data ):
isExist = True
tree.moveToNode_byNode( node )
break
if( isExist == False ):
tree.addSubNodeToCur_Data(data) pass def test():
testWzTree()
return tree = Tree()
tree.test()
return if __name__ == "__main__":
test()
python 实现树结构的更多相关文章
- python实现树结构
树在计算机科学的许多领域中使用,包括操作系统,图形,数据库系统和计算机网络.树数据结构与他们的植物表亲有许多共同之处.树数据结构具有根,分支和叶.自然界中的树和计算机科学中的树之间的区别在于树数据结构 ...
- python 实现树结构的打印
class TreeNode: def __init__(self,value): self.children = [] self.value = value def add_child(self,* ...
- 一行python代码实现树结构
树结构是一种抽象数据类型,在计算机科学领域有着非常广泛的应用.一颗树可以简单的表示为根, 左子树, 右子树. 而左子树和右子树又可以有自己的子树.这似乎是一种比较复杂的数据结构,那么真的能像我们在标题 ...
- 用python脚本通过excel生成文件夹树结构
大概这样写标题是对的吧... 目标: 通过excel目录结构文档生成文件夹树结构. 也就是: 通过下面的excel
- Python 文件复制&按目录树结构拷贝&批量删除目录及其子目录下的文件
文件复制&按目录树结构拷贝&批量删除目录及其子目录下的文件 by:授客 QQ:1033553122 测试环境: Python版本:Python 3.3.2 Win7 64 代码实践 # ...
- python 实现服务树结构化
1. 所有服务树数据 tree_list = [{'id': 1, 'pid': 0, 'name': '1211', 'path': '1211', 'leaf': 0, 'type': 0}, ...
- 【Machine Learning】决策树案例:基于python的商品购买能力预测系统
决策树在商品购买能力预测案例中的算法实现 作者:白宁超 2016年12月24日22:05:42 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本 ...
- Python多线程爬虫爬取电影天堂资源
最近花些时间学习了一下Python,并写了一个多线程的爬虫程序来获取电影天堂上资源的迅雷下载地址,代码已经上传到GitHub上了,需要的同学可以自行下载.刚开始学习python希望可以获得宝贵的意见. ...
- PYTHON解析XML的多种方式效率对比实测
在最初学习PYTHON的时候,只知道有DOM和SAX两种解析方法,但是其效率都不够理想,由于需要处理的文件数量太大,这两种方式耗时太高无法接受. 在网络搜索后发现,目前应用比较广泛,且效率相对较高的E ...
随机推荐
- java之项目构建工具Gradle
介绍 Java 作为一门世界级主流编程语言,有一款高效易用的项目管理工具是 java 开发者共同追求的心愿和目标.显示 2000 年的 Ant,后有 2004 年的 Maven 两个工具的诞生,都在 ...
- webstorm 配置 开发微信小程序
默认情况下,webstorm是不支持wxml和wxss的文件类型,不会有语法高亮 设置高亮 除了高亮,还需要代码提示, 所幸已经有前辈整理了小程序的代码片段,只需要导入其安装包即可使用,包文件路径如下 ...
- int 的重载
测试代码: 结果: 分析: 首先创建两个对象同时进行初始化所以两次调用带参的构造函数: 其次在创建一个 对象然后将其等于前两个对象相加,这里由于该类没有重载+运算符而是重载了int 所以当两个对象相加 ...
- CentOS 7 MariaDB-MHA
关于MHA MHA(Master High Availability)是一款开源的mysql高可用程序,目前在mysql高可用方面是一个相对成熟的解决方案.MHA 搭建的前提是MySQL集群中已 ...
- POJ 2154 color (polya + 欧拉优化)
Beads of N colors are connected together into a circular necklace of N beads (N<=1000000000). You ...
- Class_fourth
动手动脑 1,多层异常捕捉一 2,多层异常捕捉二 3,EmbedFinally.java示例 最先截获的错误 最后输出finally 4, SystemExitAndFinally.java示例 如果 ...
- "远程服务器返回错误: (500) 内部服务器错误"错误处理
公司购买的百傲瑞达一卡通软件,提供Restful API调用,使用SoapUI能够调用成功,但在C#里用代码调用时一直报错:"远程服务器返回错误: (500) 内部服务器错误" 找 ...
- 【数据使用】3k水稻数据库现成SNP的使用
---恢复内容开始--- 我们经常说幻想着使用已有数据发表高分文章,的确,这样的童话故事每天都在发生,但如何走出第一步我们很多小伙伴不清楚,那么我们就从水稻SNP数据库的使用来讲起. http://s ...
- Docker Swarm 介绍 or 工作原理
Docker Swarm 介绍 Swarm 简介 Swarm是Docker公司自研发的容器集群管理系统,Swarm在早期是作为一个独立服务存在,在Docker Engine v1.12中集成了Swar ...
- Mybaties 实现批量修改
通常我们在做批量更新的时候都会用in 去操作,但in的数据量一上来,就变的缓慢了 修改方案: <update id="updateShufflingSeq" paramete ...