K:树、二叉树与森林之间的转换及其相关代码实现
相关介绍:
二叉树是树的一种特殊形态,在二叉树中一个节点至多有左、右两个子节点,而在树中一个节点可以包含任意数目的子节点,对于森林,其是多棵树所组成的一个整体,树与树之间彼此相互独立,互不干扰,但其又是一个整体。树与二叉树之间、森林与二叉树之间可以相互的进行转换,且这种转换是一一对应的。树与森林转换成二叉树之后,森林与或树的相关操作都转换为二叉树的操作。在此,将讨论树的存储结构、树与森林,二叉树之间的对应关系与转换过程及相关代码。
二叉树的存储结构:
在实际应用中,可根据具体的操作的特点将树设计成不同的存储结构。但无论采用何种存储方式,都要求树的存储结构不但能够存储各个节点本身的数据域信息,还要求能准确反映树中各个节点之间的逻辑关系。于此,介绍四种链式存储方式:
1.双亲链表存储结构
双亲链表存储结构中的每一个节点存放的信息既包含节点本身的数据域信息,又包含指示双亲节点在存储结构中的位置。所以,这种存储结构可以设计成:以一组地址连续的存储单元来存放树中的各个节点,每一个节点中有两个域,一个为数据域,用来存储树中该节点本身的值;另一个是指针域,用来存储该节点的双亲节点在存储结构中的位置信息。下图演示了该存储结构:

分析: 采用双亲链表存储方式实现查找一个指定节点的双亲节点非常容易,但是要实现查找一个指定节点的孩子节点却并不容易,需要对整个链表扫描一遍
其双亲节点链表的代码描述如下:
相关代码:
public class Forest
{
	private TreeNode[] tree;
	public Forest(int n)
	{
		tree=new TreeNode[n];
	}
	class TreeNode
	{
		//数据域对象
		Object data;
		//父对象在数组中的位置
		int parent;
	}
}
2.孩子链表存储结构
孩子链表存储结构中除了存放节点本身的数据域信息之外,还存放了其所有孩子节点在存储结构中的位置信息。由于每一个节点的子节点树不同,则可将一个节点的所有孩子的位置信息按从左到右的顺序链接成一个单链表,称此单链表为该链表的孩子链表,因此,该存储结构可设计为:以一组地址连续的存储单元来存放树中的各个节点,,每一个节点有两个域,一个为数据域,用来存储树中该节点的值;另一个为指针域,用来存放该节点的孩子链表的头指针。下图演示了该存储结构:

分析:
这种存储结构与双亲链表存储结构正好相反,它便于实现查找树中指定节点的孩子节点,但不便于实现查找树中指定节点的双亲节点。
其孩子链表存储结构的示例代码如下:
相关代码:
package all_in_tree;
import java.util.LinkedList;
import java.util.List;
public class Forest
{
	private TreeNode[] tree;
	public Forest(int n)
	{
		tree=new TreeNode[n];
	}
	class TreeNode
	{
		//数据域对象
		Object data;
		//孩子链表的指针
		List firstChild=new LinkedList();
	}
}
3.双亲孩子链表存储结构
双亲孩子链表存储结构的设计方法与孩子链表存储结构类似,其主体仍然是一个存储树中各个节点信息的数组。只不过数组中的元素含有三个域,比孩子链表存储结构中多了一个存放该节点的双亲节点在数组中位置的指针域。下图演示了该存储结构:

分析:
这种存储结构既便于实现查找树中指定节点的孩子节点,又便于实现查找树中指定节点的双亲节点。
其双亲孩子链表存储结构的示例代码如下:
相关代码:
package all_in_tree;
import java.util.LinkedList;
import java.util.List;
public class Forest
{
	private TreeNode[] tree;
	public Forest(int n)
	{
		tree=new TreeNode[n];
	}
	class TreeNode
	{
		//数据域对象
		Object data;
		//双亲节点在数组中的位置
		int parent;
		//孩子链表的指针
		List firstChild=new LinkedList();
	}
}
4.孩子兄弟链表存储结构
孩子兄弟链表存储结构又称为“左孩/右兄”二叉链式存储结构,它类似于二叉树的二叉链式存储结构,不同点在于链表中每个节点的左指针是指向该节点的第一个孩子,而右指针是指向该节点的右邻兄弟。其本质就是先将一棵二叉树转化为一棵二叉树后存储在二叉链式结构之中。下图演示了该存储结构:

分析:
这种存储结构与树所对应的二叉树的二叉链式存储结构相同,一切对于树的操作都将通过这种方式转化成对二叉树的操作。为此,该种存储方式应用更加广泛
其孩子兄弟链表存储结构的示例代码如下:
相关代码:
package all_in_tree;
public class Forest
{
	private TreeNode root;
	class TreeNode
	{
		//数据域对象
		Object data;
		//其左孩子,右兄弟的指针
		TreeNode left,right;
	}
}
树转换为二叉树:
 二叉树中的节点有左右孩子之分,而在无序树中节点的各个孩子之间是无次序之分的。为了操作方便,假设树是一棵有序树,树中每个节点的孩子按照从左到右的顺序进行编号,依次定义为第一个孩子、第二个孩子、....、第i个孩子。
 将树转换为二叉树的方法可以归纳为“加线”、“删除”、”旋转“3个步骤,其具体描述如下:
- 加线:将树中所有相邻的兄弟之间加一条连线。 
- 删线:对树中的每一个节点,只保留它与第一个孩子节点之间的连线,删去它与其他孩子节点之间的连线。 
- 旋转:以树的根节点为轴心,将树平面顺时针旋转一定的角度并适当的进行调整,使得转化后所得的二叉树看起来比较规整(该步骤不是必须) 
下图给出了将树装换成二叉树的过程的示意图:

由转换过程可知,树与由它转换成的二叉树是一一对应的,树中的任意一个节点都对应着二叉树中的一个节点,树中每一个节点的第一个孩子节点在二叉树中是对应节点的左孩子,而树中每一节点的右邻兄弟在二叉树中是对应节点的右孩子(简而言之,左孩子,右兄弟)。以下,相关的代码中采用孩子链表存储结构来存储相关的树。
注意到,对于任意一个节点,其孩子链表中的第一个节点的值为其当前节点的左孩子节点;孩子链表中的任意一个节点为其下一个孩子节点的双亲节点,同时,下一个孩子节点为该节点的右孩子节点。为此,我们可以采用以下的方式,实现树与二叉树之间的相互转换
相关代码:
package all_in_tree;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
/**
 * 该类用于演示树转化为二叉树的相关代码,其中,树采用孩子链表的存储结构
 * 同时,借助一个Map,用于记录中间转化过程,以实现后期对二叉树的构造
 * @author 学徒
 *
 */
public class Forest
{
	//树中节点的数目
	private int nodeCount;
	//用于记录树中各个存储节点的指针,便于树的构造过程
	private Map<Integer,Node> nodeMap=new HashMap<Integer,Node>();
	//用于描述树的孩子链表的存储结构
	private TreeNode[] tree;
	//用于记录树的中间转化过程中的相关信息
	private MapNode[] map;
	//转化后的二叉树的根节点索引
	private Node root;
	/**
	 * 中间记录转化过程的节点
	 * @author 学徒
	 *
	 */
	class MapNode
	{
		//存储相关的数据
		Object data;
		//存储其左孩子节点在数组中的位置的下标,初始化为-1表示没有
		int left=-1;
		//存储其右孩子节点在数组中的位置的下标,初始化为-1表示没有
		int right=-1;
	}
	/**
	 * 用于创建一棵树具有n个节点的数
	 * @param n 树的节点数目
	 *
	 */
	public Forest(int n)
	{
		//存储树的节点的数目
		this.nodeCount=n;
		//用于初始化
		tree=new TreeNode[n];
		map=new MapNode[n];
		for(int i=0;i<n;i++)
		{
			tree[i]=new TreeNode();
			map[i]=new MapNode();
			nodeMap.put(i, new Node());
		}
		root=(Node)nodeMap.get(0);
	}
	/**
	 * 用于设置树中某个节点的数据域的相关值
	 * @param index 树中节点在数组中的下标
	 * @param data 树的数据域
	 */
	public void setTreeData(int index,Object data)
	{
		tree[index].data=data;
		map[index].data=data;
		nodeMap.get(index).data=data;
	}
	/**
	 * 用于增加树中某个节点的孩子节点
	 * @param index
	 * @param childIndex
	 */
	public void addTreeChild(int index,int childIndex)
	{
		if(tree[index].firstChild==null)
			tree[index].firstChild=new LinkedList<Integer>();
		tree[index].firstChild.add(childIndex);
	}
	/**
	 * 用于实现树转化为二叉树的过程,并返回该二叉树
	 *
	 */
	public Node  toTranslateBinaryTree()
	{
		//用于遍历树的双亲孩子节点存储结构的数组,同时修改和记录其中间结果的值,便于后序二叉树的构造
		for(int i=0 ;i<this.nodeCount;i++)
		{
			//孩子节点的链表
			Queue<Integer> childList=tree[i].firstChild;
			//当前孩子节点的下标编号
			int now=-1;
			//上一孩子节点的下标编号,将其默认值设置为当前节点
			int previous=i;
			//当其孩子链表存在的时候
			if(childList!=null)
			{
				//当孩子链表存在时,由于第一个节点为其当前节点的左孩子节点。为此,用于设置其左孩子节点
				if(!childList.isEmpty())
				{
					now=childList.poll();
					map[previous].left=now;
					previous=now;
				}
				//处理剩下的孩子节点
				while(!childList.isEmpty())
				{
					now=childList.poll();
					map[previous].right=now;
					previous=now;
				}
			}
		}
		//根据记录的中间结果构造出一棵二叉树
		for(int i=0;i<this.nodeCount;i++)
		{
			int left=map[i].left;
			int right=map[i].right;
			//用于获取二叉树中相关的节点
			Node node=nodeMap.get(i);
			//用于构造该二叉树
			if(left!=-1)
				node.left=nodeMap.get(left);
			if(right!=-1)
				node.right=nodeMap.get(right);
		}
		root=nodeMap.get(0);
		return root;
	}
}
/**
 * 用于存储树中双亲孩子节点的信息
 * @author 学徒
 *
 */
class TreeNode
{
	//存储相关数据
	Object  data;
/*	//其双亲节点在数组中位置的下标
	int parent;*/
	//用于存储孩子节点的孩子节点链表
	Queue<Integer> firstChild;
	/**
	 * 用于增加孩子节点的方法
	 */
	public void addChild(int child)
	{
		firstChild.add(child);
	}
}
/**
 * 二叉树中的节点描述类
 * @author 学徒
 */
class Node
{
	Object data;
	Node left;
	Node right;
}
/**
 * 用于测试使用的类,该代码采用的测试用例即为“树转换成二叉树的过程示意图”中的树
 * @author 学徒
 *
 */
class Test
{
	public static void main(String[] args)
	{
		Forest forest=new Forest(8);
		forest.setTreeData(0,"A");
		forest.setTreeData(1,"B");
		forest.setTreeData(2, "C");
		forest.setTreeData(3,"D");
		forest.setTreeData(4,"E");
		forest.setTreeData(5,"F");
		forest.setTreeData(6,"G");
		forest.setTreeData(7, "H");
		forest.addTreeChild(0, 1);
		forest.addTreeChild(0, 2);
		forest.addTreeChild(0, 3);
		forest.addTreeChild(1, 4);
		forest.addTreeChild(1, 5);
		forest.addTreeChild(5, 7);
		forest.addTreeChild(3, 6);
		Node root=forest.toTranslateBinaryTree();
		//得到二叉树中序遍历的结果
		System.out.print("中序遍历的结果 :");
		inRootTraver(root);
		System.out.println();
		//得到二叉树后序遍历的结果
		System.out.print("后序遍历的结果 :");
		postRootTraver(root);
	}
	/**
	 * 用于得到二叉树中序遍历的结果
	 */
	public static void inRootTraver(Node root)
	{
		if(root!=null)
		{
			inRootTraver(root.left);
			System.out.print(root.data+"  ");
			inRootTraver(root.right);
		}
	}
	/**
	 * 用于得到二叉树后序遍历的结果(Node root)
	 */
	public static void postRootTraver(Node root)
	{
		if(root!=null)
		{
			postRootTraver(root.left);
			postRootTraver(root.right);
			System.out.print(root.data+"  ");
		}
	}
}
其运行结果如下:
中序遍历的结果 :E  H  F  B  C  G  D  A
后序遍历的结果 :H  F  E  G  D  C  B  A 
二叉树转换成树:
二叉树转换成树是由树转换成二叉树的一个逆过程,也就是一个由二叉树还原成它原来所对应的树的过程,其步骤如下:
- 加线:若某节点是其双亲节点的左孩子,则将该节点沿着右分支向下的所有节点与该节点的双亲节点用线连接 
- 删线:将书中所有本来双亲节点与右孩子节点的连线删除 
- 旋转:对经过步骤1、2两步后所得的树以根节点为轴心,按逆时针方向旋转一定的角度并做适当调整,使得转化后所得的树看起来比较规整 
下图给出了将二叉树转化为树的过程:

以下,相关的代码中采用孩子链表存储结构来存储相关的树。
其相关的代码如下:
相关代码:
package all_in_tree;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
/**
 * 用于实现将一棵二叉树转化为树的相关操作,其中树采用孩子链表节点的存储结构
 * 同时,借助一个Map用来记录二叉树中节点和树存储结构中的数组的下标的编号的对应关系
 * @author 学徒
 *
 */
public class ReverseForest
{
	//用于记录该树二叉树
	private Node root;
	//二叉树中节点的数目
	private int nodeCount;
	//用于记录树中各个存储节点的指针,便于树的构造过程
	private Map<Integer,Node> nodeMap=new HashMap<Integer,Node>();
	//用于记录树中各个指针对应的存储节点的编号,便于树的构造
	private Map<Node,Integer> indexMap=new HashMap<Node,Integer>();
	//用于描述树的孩子链表的存储结构
	private TreeNode[] tree;
	public ReverseForest(Node root)
	{
		this.root=root;
		//对二叉树采用任意一种遍历方式,用于计算出其总节点的数目同时初始化其映射Map,此处采用层次遍历的方式
		Queue<Node> q=new LinkedList<Node>();
		q.add(root);
		nodeMap.put(this.nodeCount,root);
		indexMap.put(root,this.nodeCount++ );
		while(!q.isEmpty())
		{
			Node node = q.poll();
			if(node.left!=null)
			{
				q.add(node.left);
				nodeMap.put( this.nodeCount,node.left);
				indexMap.put(node.left,this.nodeCount++);
			}
			if(node.right!=null)
			{
				q.add(node.right);
				nodeMap.put(this.nodeCount,node.right);
				indexMap.put(node.right, this.nodeCount++);
			}
		}
		//初始化其孩子链表的存储结构
		tree=new TreeNode[this.nodeCount];
		//用于初始化各个树中的节点
		for(Entry<Integer,Node> node:nodeMap.entrySet())
		{
			int index=node.getKey();
			tree[index]=new TreeNode();
			tree[index].data=node.getValue().data;
		}
	}
	/**
	 * 用于增加树中某个节点的孩子节点
	 * @param index
	 * @param childIndex
	 */
	public void addTreeChild(int index,int childIndex)
	{
		if(tree[index].firstChild==null)
			tree[index].firstChild=new LinkedList<Integer>();
		tree[index].firstChild.add(childIndex);
	}
	/**
	 * 用于将二叉树转化为树
	 */
	public TreeNode[] toTranslateTree()
	{
		//用于遍历描述树的数组
		for(int index=0;index<this.nodeCount;index++)
		{
			//得到该树节点
			Node node=nodeMap.get(index);
			//得到该树节点所对应的第一个孩子节点
			node=node.left;
			if(node!=null)
			{
				addTreeChild(index,indexMap.get(node));
				while(node.right!=null)
				{
					addTreeChild(index, indexMap.get(node.right));
					node=node.right;
				}
			}
		}
		return this.tree;
	}
}
class Tests
{
	/**
	 * 测试代码,用于测试其运行结果
	 * @param args
	 */
	public static void main(String[] args)
	{
		TreeNode[] tree= new ReverseForest(Test.test()).toTranslateTree();
		System.out.println();
		for(int i=0;i<tree.length;i++)
		{
			System.out.print(i+(tree[i].data.toString())+": ");
			Queue<Integer> q=tree[i].firstChild;
			if(q!=null)
			{
				Iterator iterator =q.iterator();
				while(iterator.hasNext())
				{
					System.out.print(iterator.next()+"   ");
				}
			}
			else
			{
				System.out.print("无孩子节点");
			}
			System.out.println();
		}
	}
}
/**
 * 用于存储树中双亲孩子节点的信息
 * @author 学徒
 *
 */
class TreeNode
{
	//存储相关数据
	Object  data;
	//用于存储孩子节点的孩子节点链表
	Queue<Integer> firstChild;
	/**
	 * 用于增加孩子节点的方法
	 */
	public void addChild(int child)
	{
		firstChild.add(child);
	}
}
/**
 * 二叉树中的节点描述类
 * @author 学徒
 */
class Node
{
	Object data;
	Node left;
	Node right;
}
/**
 * 用于测试使用的类,该代码采用的测试用例即为“树转换成二叉树的过程示意图”中的树
 * @author 学徒
 *
 */
class Test
{
	public static Node test()
	{
		Forest forest=new Forest(8);
		forest.setTreeData(0,"A");
		forest.setTreeData(1,"B");
		forest.setTreeData(2, "C");
		forest.setTreeData(3,"D");
		forest.setTreeData(4,"E");
		forest.setTreeData(5,"F");
		forest.setTreeData(6,"G");
		forest.setTreeData(7, "H");
		forest.addTreeChild(0, 1);
		forest.addTreeChild(0, 2);
		forest.addTreeChild(0, 3);
		forest.addTreeChild(1, 4);
		forest.addTreeChild(1, 5);
		forest.addTreeChild(5, 7);
		forest.addTreeChild(3, 6);
		Node root=forest.toTranslateBinaryTree();
		//得到二叉树中序遍历的结果
		System.out.print("中序遍历的结果 :");
		inRootTraver(root);
		System.out.println();
		//得到二叉树后序遍历的结果
		System.out.print("后序遍历的结果 :");
		postRootTraver(root);
		return root;
	}
	/**
	 * 用于得到二叉树中序遍历的结果
	 */
	public static void inRootTraver(Node root)
	{
		if(root!=null)
		{
			inRootTraver(root.left);
			System.out.print(root.data+"  ");
			inRootTraver(root.right);
		}
	}
	/**
	 * 用于得到二叉树后序遍历的结果(Node root)
	 */
	public static void postRootTraver(Node root)
	{
		if(root!=null)
		{
			postRootTraver(root.left);
			postRootTraver(root.right);
			System.out.print(root.data+"  ");
		}
	}
}
运行结果:
中序遍历的结果 :E  H  F  B  C  G  D  A
后序遍历的结果 :H  F  E  G  D  C  B  A
0A: 1   3   5
1B: 2   4
2E: 无孩子节点
3C: 无孩子节点
4F: 6
5D: 7
6H: 无孩子节点
7G: 无孩子节点
森林转换成二叉树:
森林是若干棵树的集合,而任何一棵和树对应的二叉树其根节点的右子树一定为空,因而可得到将森林转换成二叉树的方法如下:
- 将森林中的每棵树转换成相应的二叉树
- 按照森林中树的先后顺序,将一棵二叉树视为前一棵二叉树的右子树依次连接起来,从而构成一棵二叉树
下图给出了将森林转换为二叉树的过程:

从中可以看出,森林与二叉树之间存在着一一对应的关系。森林中第一棵树的根节点对应着二叉树的根节点;森林中第一棵树的根节点的子树所构成的森林对应着二叉树的左子树;森林中除第一棵树之外的其它树所构成的森林所对应着二叉树的右子树。
除了将每棵树转化为相应的二叉树,之后按照森林中树的先后顺序,将一棵二叉树视为前一棵二叉树的右子树依次连接起来,构成一棵二叉树的方法之外,还存在着一种增加一个虚节点,之后将森林转化成一棵树,然后再按照将树转化成二叉树的方式转化成二叉树的方法
下图给出了增加一个虚节点将森林转换成二叉树的过程:

森林转化为二叉树的代码与树转化为二叉树的代码基本相同,此处不再重复
二叉树转换成森林:
二叉树与森林之间存在着一一对应的关系,可以根据以下步骤将一棵二叉树转化为森林:
- 将二叉树的根节点的右孩子节点的各个连线之间依次断开,将一棵二叉树分解为多棵二叉树 
- 依次将每一棵二叉树通过加线、删线、旋转的方式转换为一棵树 
- 各个树构成的整体即为一个森林 
下图给出了将一棵二叉树转化为森林的过程:

二叉树转化为森林的代码与二叉树转化为树的代码基本相同,此处不再重复
K:树、二叉树与森林之间的转换及其相关代码实现的更多相关文章
- 树形DP+(分组背包||二叉树,一般树,森林之间的转换)codevs 1378 选课
		codevs 1378 选课 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 学校实行学分制.每门的必修课都有固定的学分 ... 
- 树&二叉树&哈夫曼树
		1.树 需要注意的两点:n(n>=0)表示结点的个数,m表示子树的个数 (1)n>0时,树的根节点是唯一的. (2)m>0时,子树的个数没有限制. 结点的度和树的度 (1)结点的度是 ... 
- K:二叉树
		相关介绍: 二叉树是一种特殊的树,它的每个节点最多只有两棵子树,并且这两棵子树也是二叉树.由于二叉树中的两棵子树有左右之分,为此,二叉树是有序树. 二叉树的定义: 二叉树是由n(n>=0)个 ... 
- 树&二叉树&&满二叉树&&完全二叉树&&完满二叉树
		目录 树 二叉树 完美二叉树(又名满二叉树)(Perfect Binary Tree) 完全二叉树(Complete Binary Tree) 完满二叉树(Full Binary Tree) 树 名称 ... 
- iOS全角符与半角符之间的转换
		iOS全角符与半角符之间的转换 相关资料: 函数『CFStringTransform』中文 详情: 问题 1.17-03-15,「有人在群里边问怎么把『半角』符字符串转换成『全角』字符串?」,百度的 ... 
- FFMPEG 实现 YUV,RGB各种图像原始数据之间的转换(swscale)
		FFMPEG中的swscale提供了视频原始数据(YUV420,YUV422,YUV444,RGB24...)之间的转换,分辨率变换等操作,使用起来十分方便,在这里记录一下它的用法. swscale主 ... 
- Java中String与Date格式之间的转换
		转自:https://blog.csdn.net/angus_17/article/details/7656631 经常遇到string和date之间的转换,把相关的内容总结在这里吧: 1.strin ... 
- 实体类与实体DTO类之间的转换
		实体类与实体DTO类之间的转换 实体类与实体DTO类之间的转换 1.通过使用第三方序列化反序列化工具Newtonsoft.Json 2.通过反射实现 3.通过表达式目录树加字典缓存实现 4. 通过表达 ... 
- java中unicode utf-8以及汉字之间的转换工具类
		1. 汉字字符串与unicode之间的转换 1.1 stringToUnicode /** * 获取字符串的unicode编码 * 汉字"木"的Uni ... 
随机推荐
- ML学习分享系列(2)_计算广告小窥[中]
			原作:面包包包包包包 改动:寒小阳 && 龙心尘 时间:2016年2月 出处:http://blog.csdn.net/Breada/article/details/50697030 ... 
- 深入理解JSP
			JSP(Java server page)是Java EE规范最基本成员,他是Java Web开发的重点知识,尽管我们一直在用.但其原理知之甚少.今天重点研究一些JSP核心内容以及其工作原理. JSP ... 
- Linux chgrp
			在学习 兄弟连 linux教学视频 的时候,我将所学的 linux 命令记录在我的博客中,方便自己查阅. 权限管理命令: chgrp 基础的命令 命令名称:chgrp 命令英文原意:change fi ... 
- Django ModelForm修改默认的控件属性
			Django 中利用ModelForm 可以快速地利用数据库对应的Model 子类来自动创建对应表单. 例如: from django.db import models from django.for ... 
- VM虚拟机连Linux黑屏问题
			在尝试了关闭VM的加速3D图形后,若仍黑屏(但是挂起时却能显示),可以尝试在以管理员身份cmd中输入netsh winsock reset,重启后可以恢复正常.这个问题似乎与网络某个端口有关,我上次打 ... 
- Git远程库版本回滚
			在git的一般使用中,如果发现错误的将不想staging的文件add进入index之后,想回退取消,这就叫做git代码库回滚: 指的是将代码库某分支退回到以前的某个commit id.可以使用命令:g ... 
- Mybatis篇总结
			本文是对慕课网上"搞定SSM开发"路径的系列课程的总结,详细的项目文档和课程总结放在github上了.点击查看 JDBC写法 //sql: String sql = "s ... 
- Akka Cluster简介与基本环境搭建
			akka集群是高容错.去中心化.不存在单点故障以及不存在单点瓶颈的集群.它使用gossip协议通信以及具备故障自动检测功能. Gossip收敛 集群中每一个节点被其他节点监督(默认的最大数量为 ... 
- webpack 理解
			目录 关于此文 在学习webpack之前,我们先去了解它的作用 它与其他其他前端工具(gulp,grunt)有什么差别呢 安装 webpack.config.js 配置结果 webpack 开始简单配 ... 
- 理解Kubernetes(1):手工搭建Kubernetes测试环境
			系列文章: 1. 手工搭建环境 1. 基础环境准备 准备 3个Ubuntu节点,操作系统版本为 16.04,并做好以下配置: 系统升级 设置 /etc/hosts 文件,保持一致 设置从 0 节点上无 ... 
