zoukankan      html  css  js  c++  java
  • BFS (1)算法模板 看是否需要分层 (2)拓扑排序——检测编译时的循环依赖 制定有依赖关系的任务的执行顺序 djkstra无非是将bfs模板中的deque修改为heapq

    BFS模板,记住这5个:
    (1)针对树的BFS
    1.1 无需分层遍历
        from collections import deque
    	
        def levelOrderTree(root):
            if not root:
                return 
                 
            q = deque([root])
            while q:
                head = q.popleft()
    			do something with this head node...
                if head.left:                
                    q.append(head.left)
    			if head.right:
                    q.append(head.right)                
            return xxx
    1.2 需要分层遍历
        def levelOrderTree(root):
            if not root:
                return
                     
            q = [root]
            while q:
                new_q = []
                for node in q: # 和上面代码相比 差异就在这里 和 deque
                    do something with this layer nodes...
                    if node.left:
                        new_q.append(node.left)
                    if node.right:
                        new_q.append(node.right)            
                q = new_q
            return xxx
    		
    (2)针对图的BFS
    2.1 无需分层遍历
      from collections import deque
      
      def bfs_graph(root):	
        if not root: 
    	    return
    	
    	queue = deque([root])
    	seen = set([root])  
    	while queue:
    		head = queue.popleft()
    		do something with this head...
    		for neighbor in head.neighbors:
    			if neighbor not in seen: # 和tree的区别无非就是多了一个是否访问过的判断
    				seen.add(neighbor)
    				queue.append(neighbor)
      return xxx
    
    上述代码中:
    neighbor 表示从某个点 head 出发,可以走到的下一层的节点。
    set/seen 存储已经访问过的节点(已经丢到 queue 里去过的节点)
    queue 存储等待被拓展到下一层的节点
    set/seen 与 queue 是一对好基友,无时无刻都一起出现,往 queue 里新增一个节点,就要同时丢到 set 里。
    需要分层遍历的宽度搜先搜索
    
    2.2 需分层遍历
    
        def bfs_graph(root):
            if not root:
                return []
                     
            q = [root]
    		seen = set([root])
            while q:
                new_q = []
                for node in q:
                    do something with this layer nodes...				
    				for neighbor in node.neighbors:
    				    if neighbor not in seen: # 和tree的区别无非就是多了一个是否访问过的判断
    					    seen.add(neighbor)
    						new_q.append(neighbor)           
                q = new_q
            return xxx
    
    
    (3)拓扑排序
    
    记住下面的代码
    class Solution:
        """
        @param graph: A list of Directed graph node
        @return: Any topological order for the given graph.
        """
        def topSort(self, graph):
            node_to_indegree = self.get_indegree(graph)
     
            # bfs
            order = []
            start_nodes = [n for n in graph if node_to_indegree[n] == 0]
            queue = collections.deque(start_nodes)
            while queue:
                node = queue.popleft()
                order.append(node)
                for neighbor in node.neighbors:
                    node_to_indegree[neighbor] -= 1
                    if node_to_indegree[neighbor] == 0:
                        queue.append(neighbor)
                     
            return order
         
        def get_indegree(self, graph):
            node_to_indegree = {x: 0 for x in graph}
     
            for node in graph:
                for neighbor in node.neighbors:
                    node_to_indegree[neighbor] += 1
                     
            return node_to_indegree
    
    算法流程
    拓扑排序的算法是典型的宽度优先搜索算法,其大致流程如下:
    统计所有点的入度,并初始化拓扑序列为空。
    将所有入度为 0 的点,也就是那些没有任何依赖的点,放到宽度优先搜索的队列中
    将队列中的点一个一个的释放出来,放到拓扑序列中,每次释放出某个点 A 的时候,就访问 A 的相邻点(所有A指向的点),并把这些点的入度减去 1。
    如果发现某个点的入度被减去 1 之后变成了 0,则放入队列中。
    直到队列为空时,算法结束		
    
    
    一些实际案例:
    https://www.cnblogs.com/bonelee/p/11724346.html
    

      

    69. 二叉树的层次遍历

    中文English

    给出一棵二叉树,返回其节点值的层次遍历(逐层从左往右访问)

    Example

    样例 1:

    输入:{1,2,3}
    输出:[[1],[2,3]]
    解释:
       1
      / 
     2   3
    它将被序列化为{1,2,3}
    层次遍历
    

    样例 2:

    输入:{1,#,2,3}
    输出:[[1],[2],[3]]
    解释:
    1
     
      2
     /
    3
    它将被序列化为{1,#,2,3}
    层次遍历
    

    Challenge

    挑战1:只使用一个队列去实现它

    挑战2:用BFS算法来做

    Notice

    • 首个数据为根节点,后面接着是其左儿子和右儿子节点值,"#"表示不存在该子节点。
    • 节点数量不超过20。
    """
    Definition of TreeNode:
    class TreeNode:
        def __init__(self, val):
            self.val = val
            self.left, self.right = None, None
    """
    
    
    class Solution:
        """
        @param root: A Tree
        @return: Level order a list of lists of integer
        """
        def levelOrder(self, root):
            # write your code here
            if not root:
                return []
                
            q = [root]
            result = []
            while q:
                children = []
                q2 = []
                for node in q:
                    children.append(node.val)
                    if node.left:
                        q2.append(node.left)
                    if node.right:    
                        q2.append(node.right)
                result.append(children)
                q = q2
            return result
                    
    

    71. 二叉树的锯齿形层次遍历

    中文
    English

    给出一棵二叉树,返回其节点值的锯齿形层次遍历(先从左往右,下一层再从右往左,层与层之间交替进行) 

    样例

    样例 1:

    输入:{1,2,3}
    输出:[[1],[3,2]]
    解释:
        1
       / 
      2   3
    它将被序列化为 {1,2,3}
    

    样例 2:

    输入:{3,9,20,#,#,15,7}
    输出:[[3],[20,9],[15,7]]
    解释:
        3
       / 
      9  20
        /  
       15   7
    它将被序列化为 {3,9,20,#,#,15,7}
    
    """
    Definition of TreeNode:
    class TreeNode:
        def __init__(self, val):
            self.val = val
            self.left, self.right = None, None
    """
    
    class Solution:
        """
        @param root: A Tree
        @return: A list of lists of integer include the zigzag level order traversal of its nodes' values.
        """
        def zigzagLevelOrder(self, root):
            # write your code here
            if not root:
                return []
            
            q = [root]
            result = []
            layer = 0
            while q:
                q2 = []
                values = []
                for node in q:
                    values.append(node.val)
                    if node.left:
                        q2.append(node.left)
                    if node.right:
                        q2.append(node.right)
                if layer % 2 == 0:
                    result.append(values)
                else:
                    result.append(values[::-1])
                q = q2
                layer += 1
            return result
                    
    

    70. 二叉树的层次遍历 II

    中文
    English

    给出一棵二叉树,返回其节点值从底向上的层次序遍历(按从叶节点所在层到根节点所在的层遍历,然后逐层从左往右遍历)

    样例

    例1:

    输入:
    {1,2,3}
    输出:
    [[2,3],[1]]
    解释:
        1
       / 
      2   3
    它将被序列化为 {1,2,3}
    层次遍历
    

    例2:

    输入:
    {3,9,20,#,#,15,7}
    输出:
    [[15,7],[9,20],[3]]
    解释:
        3
       / 
      9  20
        /  
       15   7
    它将被序列化为 {3,9,20,#,#,15,7}
    层次遍历
    
    """
    Definition of TreeNode:
    class TreeNode:
        def __init__(self, val):
            self.val = val
            self.left, self.right = None, None
    """
    
    class Solution:
        """
        @param root: A tree
        @return: buttom-up level order a list of lists of integer
        """
        def levelOrderBottom(self, root):
            # write your code here
            # write your code here
            if not root:
                return []
            
            result = []
            q = [root]
            while q:
                new_q = []
                values = []
                for node in q:
                    values.append(node.val)
                    if node.left:
                        new_q.append(node.left)
                    if node.right:
                        new_q.append(node.right)
                result.append(values)
                q = new_q
            return result[::-1]
    

    137. 克隆图

    中文
    English

    克隆一张无向图. 无向图的每个节点包含一个 label 和一个列表 neighbors. 保证每个节点的 label 互不相同.

    你的程序需要返回一个经过深度拷贝的新图. 新图和原图具有同样的结构, 并且对新图的任何改动不会对原图造成任何影响.

    样例

    样例1

    输入:
    {1,2,4#2,1,4#4,1,2}
    输出: 
    {1,2,4#2,1,4#4,1,2}
    解释:
    1------2  
          |  
          |  
          |  
          |  
          4   
    

    说明

    关于无向图的表示: http://www.lintcode.com/help/graph/

    注意事项

    你需要返回与给定节点具有相同 label 的那个节点.

    """
    Definition for a undirected graph node
    class UndirectedGraphNode:
        def __init__(self, x):
            self.label = x
            self.neighbors = []
    """
    
    from collections import deque
    
    
    class Solution:
        """
        @param: node: A undirected graph node
        @return: A undirected graph node
        """
        def cloneGraph(self, root):
            # write your code here
            if not root:
                return None
            
            """
            使用宽度优先搜索 BFS 的版本。
            第一步:找到所有独一的点
            第二步:复制所有的点,将映射关系存起来
            第三步:找到所有的边,复制每一条边
            """
            nodes = self.get_unique_nodes(root)
            mapping_nodes = self.copy_nodes(nodes)
            self.copy_edges(nodes, mapping_nodes)
            return mapping_nodes[root]
            
        
        def get_unique_nodes(self, root):
            q, seen = deque([root]), set([root])
            while q:
                node = q.popleft()
                for neighbor_node in node.neighbors:
                    if neighbor_node not in seen:
                        seen.add(neighbor_node)
                        q.append(neighbor_node)
            return seen
        
        
        def copy_nodes(self, nodes):
            return {node: UndirectedGraphNode(node.label) for node in nodes}
        
        
        def copy_edges(self, nodes, mapping_nodes):
            for node in nodes:
                copied_node = mapping_nodes[node]
                for neighbor in node.neighbors:
                    copied_node.neighbors.append(mapping_nodes[neighbor])
                    
    

    120. 单词接龙

    中文
    English

    给出两个单词(startend)和一个字典,找出从startend的最短转换序列,输出最短序列的长度。

    变换规则如下:

    1. 每次只能改变一个字母。
    2. 变换过程中的中间单词必须在字典中出现。(起始单词和结束单词不需要出现在字典中)

    样例

    样例 1:

    输入:start = "a",end = "c",dict =["a","b","c"]
    输出:2
    解释:
    "a"->"c"
    

    样例 2:

    输入:start ="hit",end = "cog",dict =["hot","dot","dog","lot","log"]
    输出:5
    解释:
    "hit"->"hot"->"dot"->"dog"->"cog"
    

    注意事项

    • 如果不存在这样的转换序列,返回 0。
    • 所有单词具有相同的长度。
    • 所有单词只由小写字母组成。
    • 字典中不存在重复的单词。
    • 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
    class Solution:
        """
        @param: start: a string
        @param: end: a string
        @param: dict: a set of string
        @return: An integer
        """
        def ladderLength(self, start, end, dict):
            dict.add(end)
            q = [start]
            visited = set([start])
            
            distance = 0
            while q:
                distance += 1
                new_q = []
                for word in q:
                    if word == end:
                        return distance
                    
                    for next_word in self.get_next_words(word):
                        if next_word not in dict or next_word in visited:
                            continue
                        new_q.append(next_word)
                        visited.add(next_word) 
                q = new_q
    
            return 0
            
        # O(26 * L^2)
        # L is the length of word
        def get_next_words(self, word):
            words = []
            for i in range(len(word)):
                left, right = word[:i], word[i + 1:]
                for char in 'abcdefghijklmnopqrstuvwxyz':
                    if word[i] == char:
                        continue
                    words.append(left + char + right)
            return words        
    

      



    7. 二叉树的序列化和反序列化

    中文
    English

    设计一个算法,并编写代码来序列化和反序列化二叉树。将树写入一个文件被称为“序列化”,读取文件后重建同样的二叉树被称为“反序列化”。

    如何反序列化或序列化二叉树是没有限制的,你只需要确保可以将二叉树序列化为一个字符串,并且可以将字符串反序列化为原来的树结构。

    样例

    样例 1:

    输入:{3,9,20,#,#,15,7}
    输出:{3,9,20,#,#,15,7}
    解释:
    二叉树 {3,9,20,#,#,15,7},表示如下的树结构:
    	  3
    	 / 
    	9  20
    	  /  
    	 15   7
    它将被序列化为 {3,9,20,#,#,15,7}
    

    样例 2:

    输入:{1,2,3}
    输出:{1,2,3}
    解释:
    二叉树 {1,2,3},表示如下的树结构:
       1
      / 
     2   3
    它将被序列化为 {1,2,3}
    

    我们的数据是进行 BFS 遍历得到的。当你测试结果 Wrong Answer 时,你可以作为输入调试你的代码。

    你可以采用其他的方法进行序列化和反序列化。

    注意事项

    对二进制树进行反序列化或序列化的方式没有限制,LintCode 将您的 serialize 输出作为 deserialize 的输入,它不会检查序列化的结果。

    """
    Definition of TreeNode:
    class TreeNode:
        def __init__(self, val):
            self.val = val
            self.left, self.right = None, None
    """
    
    from collections import deque
    
    
    class Solution:
        """
        @param root: An object of TreeNode, denote the root of the binary tree.
        This method will be invoked first, you should design your own algorithm 
        to serialize a binary tree which denote by a root node to a string which
        can be easily deserialized by your own "deserialize" method later.
        """
        def serialize(self, root):
            # write your code here
            if not root:
                return []
                
            q = deque([root])
            result = []
            while q:
                head = q.popleft()
                if head:
                    result.append(str(head.val))
                    q.append(head.left)
                    q.append(head.right)
                else:
                    result.append('#')
                    
            while result and result[-1] == '#':
                result.pop()
                
            return result
            
    
        """
        @param data: A string serialized by your serialize method.
        This method will be invoked second, the argument data is what exactly
        you serialized at method "serialize", that means the data is not given by
        system, it's given by your own serialize method. So the format of data is
        designed by yourself, and deserialize it here as you serialize it in 
        "serialize" method.
        """
        def deserialize(self, data):
            # write your code here
            if not data:
                return None
            
            root = TreeNode(data[0])
            q = deque([root])
            i = 1
            while q and i < len(data):
                head = q.popleft()
                if data[i] != '#':
                    head.left = TreeNode(data[i])
                    q.append(head.left)
                i += 1
                if data[i] != '#':
                    head.right = TreeNode(data[i])
                    q.append(head.right)
                i += 1
            return root
    

    433. 岛屿的个数

    中文
    English

    给一个 01 矩阵,求不同的岛屿的个数。

    0 代表海,1 代表岛,如果两个 1 相邻,那么这两个 1 属于同一个岛。我们只考虑上下左右为相邻。

    样例

    样例 1:

    输入:
    [
      [1,1,0,0,0],
      [0,1,0,0,1],
      [0,0,0,1,1],
      [0,0,0,0,0],
      [0,0,0,0,1]
    ]
    输出:
    3
    

    样例 2:

    输入:
    [
      [1,1]
    ]
    输出:
    1
    
    from collections import deque
    
    
    class Solution:
        """
        @param grid: a boolean 2D matrix
        @return: an integer
        """
        def numIslands(self, grid):
            if not grid or not grid[0]:
                return 0
                
            islands = 0
            visited = set()
            for i in range(len(grid)):
                for j in range(len(grid[0])):
                    if grid[i][j] and (i, j) not in visited:
                        self.bfs(grid, i, j, visited)
                        islands += 1
                        
            return islands                    
        
        def bfs(self, grid, x, y, visited):
            queue = deque([(x, y)])
            visited.add((x, y))
            while queue:
                x, y = queue.popleft()
                for delta_x, delta_y in [(1, 0), (0, -1), (-1, 0), (0, 1)]:
                    next_x = x + delta_x
                    next_y = y + delta_y
                    if not self.is_valid(grid, next_x, next_y, visited):
                        continue
                    queue.append((next_x, next_y))
                    visited.add((next_x, next_y))
    
        def is_valid(self, grid, x, y, visited):
            n, m = len(grid), len(grid[0])
            if not (0 <= x < n and 0 <= y < m):
                return False
            if (x, y) in visited:
                return False
            return grid[x][y]
    

    611. 骑士的最短路线

    中文
    English

    给定骑士在棋盘上的 初始 位置(一个2进制矩阵 0 表示空 1 表示有障碍物),找到到达 终点 的最短路线,返回路线的长度。如果骑士不能到达则返回 -1

    样例

    例1:

    输入:
    [[0,0,0],
     [0,0,0],
     [0,0,0]]
    source = [2, 0] destination = [2, 2] 
    输出: 2
    解释:
    [2,0]->[0,1]->[2,2]
    

    例2:

    输入:
    [[0,1,0],
     [0,0,1],
     [0,0,0]]
    source = [2, 0] destination = [2, 2] 
    输出:-1
    

    说明

    如果骑士的位置为 (x,y),他下一步可以到达以下这些位置:

    (x + 1, y + 2)
    (x + 1, y - 2)
    (x - 1, y + 2)
    (x - 1, y - 2)
    (x + 2, y + 1)
    (x + 2, y - 1)
    (x - 2, y + 1)
    (x - 2, y - 1)
    

    注意事项

    起点跟终点必定为空.
    骑士不能碰到障碍物.
    路径长度指骑士走的步数.

    """
    Definition for a point.
    class Point:
        def __init__(self, a=0, b=0):
            self.x = a
            self.y = b
    """
    
    DIRECTIONS = [
        (-2, -1), (-2, 1), (-1, 2), (1, 2),
        (2, 1), (2, -1), (1, -2), (-1, -2),
    ]
    
    class Solution:
            
        """
        @param grid: a chessboard included 0 (false) and 1 (true)
        @param source: a point
        @param destination: a point
        @return: the shortest path 
        """
        def shortestPath(self, grid, source, destination):
            queue = collections.deque([(source.x, source.y)])
            distance = {(source.x, source.y): 0}
    
            while queue:
                x, y = queue.popleft()
                if (x, y) == (destination.x, destination.y):
                    return distance[(x, y)]
                for dx, dy in DIRECTIONS:
                    next_x, next_y = x + dx, y + dy
                    if (next_x, next_y) in distance:
                        continue
                    if not self.is_valid(next_x, next_y, grid):
                        continue
                    distance[(next_x, next_y)] = distance[(x, y)] + 1
                    queue.append((next_x, next_y))
            return -1
            
        def is_valid(self, x, y, grid):
            n, m = len(grid), len(grid[0])
    
            if x < 0 or x >= n or y < 0 or y >= m:
                return False
                
            return not grid[x][y]
    

    djkstra最短路问题,其实就是bfs不分层的模板,无非就是将deque修改为heapq而已,heapq中记录了路径距离优先级(下面程序如果不要path则去掉即可)

    import heapq
    
    
    def shortest_path(graph, start, end):
        queue,seen = [(0, start, [])], {start}
        while queue:
            cost, v, path = heapq.heappop(queue)
            path = path + [v]
            if v == end:
                return cost, path
            for (neighbor_node, c) in graph[v].items():
                if neighbor_node not in seen:
                    seen.add(neighbor_node)
                    heapq.heappush(queue, (cost + c, neighbor_node, path))
        return -1, []
    
    graph = {
    'a': {'w': 14, 'x': 7, 'y': 9},
    'b': {'w': 9, 'z': 6},
    'w': {'a': 14, 'b': 9, 'y': 2},
    'x': {'a': 7, 'y': 10, 'z': 10},
    'y': {'a': 9, 'w': 2, 'x': 10, 'z': 11},
    'z': {'b': 6, 'x': 15, 'y': 11},
    }
    cost, path = shortest_path(graph, start='a', end='z')
    print(cost, path)  
    

      

    拓扑排序定义

    在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序(英语:Topological sorting)。

    • 每个顶点出现且只出现一次;
    • 若A在序列中排在B的前面,则在图中不存在从B到A的路径。

    也可以定义为:拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从顶点A到顶点B的路径,那么在排序中B出现在A的后面。

    (来自 Wiki)

    实际运用

    拓扑排序 Topological Sorting 是一个经典的图论问题。他实际的运用中,拓扑排序可以做如下的一些事情:

    • 检测编译时的循环依赖
    • 制定有依赖关系的任务的执行顺序

    拓扑排序不是一种排序算法

    虽然名字里有 Sorting,但是相比起我们熟知的 Bubble Sort, Quick Sort 等算法,Topological Sorting 并不是一种严格意义上的 Sorting Algorithm。

    确切的说,一张图的拓扑序列可以有很多个,也可能没有。拓扑排序只需要找到其中一个序列,无需找到所有序列。

    入度与出度

    在介绍算法之前,我们先介绍图论中的一个基本概念,入度出度,英文为 in-degree & out-degree。
    在有向图中,如果存在一条有向边 A-->B,那么我们认为这条边为 A 增加了一个出度,为 B 增加了一个入度。

    算法流程

    拓扑排序的算法是典型的宽度优先搜索算法,其大致流程如下:

    1. 统计所有点的入度,并初始化拓扑序列为空。
    2. 将所有入度为 0 的点,也就是那些没有任何依赖的点,放到宽度优先搜索的队列中
    3. 将队列中的点一个一个的释放出来,放到拓扑序列中,每次释放出某个点 A 的时候,就访问 A 的相邻点(所有A指向的点),并把这些点的入度减去 1。
    4. 如果发现某个点的入度被减去 1 之后变成了 0,则放入队列中。
    5. 直到队列为空时,算法结束,

    深度优先搜索的拓扑排序

    深度优先搜索也可以做拓扑排序,不过因为不容易理解,也并不推荐作为拓扑排序的主流算法。

    127. 拓扑排序

    中文English

    给定一个有向图,图节点的拓扑排序定义如下:

    • 对于图中的每一条有向边 A -> B , 在拓扑排序中A一定在B之前.
    • 拓扑排序中的第一个节点可以是图中的任何一个没有其他节点指向它的节点.

    针对给定的有向图找到任意一种拓扑排序的顺序.

    Example

     

    Challenge

    能否分别用BFS和DFS完成?

    Notice

    你可以假设图中至少存在一种拓扑排序

    """
    Definition for a Directed graph node
    class DirectedGraphNode:
        def __init__(self, x):
            self.label = x
            self.neighbors = []
    """
    
    class Solution:
        """
        @param graph: A list of Directed graph node
        @return: Any topological order for the given graph.
        """
        def topSort(self, graph):
            node_to_indegree = self.get_indegree(graph)
    
            # bfs
            order = []
            start_nodes = [n for n in graph if node_to_indegree[n] == 0]
            queue = collections.deque(start_nodes)
            while queue:
                node = queue.popleft()
                order.append(node)
                for neighbor in node.neighbors:
                    node_to_indegree[neighbor] -= 1
                    if node_to_indegree[neighbor] == 0:
                        queue.append(neighbor)
                    
            return order
        
        def get_indegree(self, graph):
            node_to_indegree = {x: 0 for x in graph}
    
            for node in graph:
                for neighbor in node.neighbors:
                    node_to_indegree[neighbor] += 1
                    
            return node_to_indegree
    

    615. 课程表

    中文
    English

    现在你总共有 n 门课需要选,记为 0n - 1.
    一些课程在修之前需要先修另外的一些课程,比如要学习课程 0 你需要先学习课程 1 ,表示为[0,1]
    给定n门课以及他们的先决条件,判断是否可能完成所有课程?

    样例

    例1:

    输入: n = 2, prerequisites = [[1,0]] 
    输出: true
    

    例2:

    输入: n = 2, prerequisites = [[1,0],[0,1]] 
    输出: false
    
    from collections import deque
    
    
    class Solution:
        # @param {int} numCourses a total of n courses
        # @param {int[][]} prerequisites a list of prerequisite pairs
        # @return {boolean} true if can finish all courses or false
        def canFinish(self, numCourses, prerequisites):
            # Write your code here
            edges = {i: [] for i in range(numCourses)}
            degrees = [0 for i in range(numCourses)] 
            for i, j in prerequisites:
                edges[j].append(i)
                degrees[i] += 1
                
            queue, count = deque([]), 0
            
            for i in range(numCourses):
                if degrees[i] == 0:
                    queue.append(i)
    
            while queue:
                node = queue.popleft()
                count += 1
    
                for x in edges[node]:
                    degrees[x] -= 1
                    if degrees[x] == 0:
                        queue.append(x)
    
            return count == numCourses
    

      

  • 相关阅读:
    个人网站第一期完成
    nodebb在阿里云主机部署过程
    mongoengine教程1
    quick cocos 的scheduler 定时器
    cocos2dx调度器scheduler
    Cocos2d-x中Vector使用
    Google分布式系统三驾马车: GFS,mapreduce,Bigtable
    Linux使用记
    Eclipse快捷键总结
    详解iOS App生命周期(转)
  • 原文地址:https://www.cnblogs.com/bonelee/p/11724346.html
Copyright © 2011-2022 走看看