树论基础
树是数据结构和算法分析与设计中的一种非常重要的结构,由N个节点组成的
具有层次结构的模型。其主要有以下几个特点:
- 有一个根节点,一般称为root节点
- 每一个元素都被称为node
- 除了root节点外,其余的节点都会被分成n个互不相交的集合,子树。
树形结构里面的基本术语:
- 结点:树形结构里面的元素
- 子树:当结点大于1时,其余的结点分为的互不相交的集合称为子树
- 度:一个结点拥有的子树数量称为结点的度
- 叶子:度为0的结点
- 孩子:结点的子树的根称为孩子结点
- 双亲:和孩子结点对应
- 兄弟:同一个双亲结点
- 深度:结点的最大层次称为树的深度,计算时间复杂度用
- 森林:由N个互不相交的树构成深林
二叉树
二叉树(Binary Tree):一种特殊的树形结构,每个节点至多只有两颗子树
下面的除了1都属于二叉树
在二叉树的第N层上至多有2^(N-1)个结点。最多有2^N-1个结点个数
满二叉树(完全二叉树):假设树的深度为M,其有2^M-1个jie点的二叉树,假如深度为3,那么就有2^3 – 1 =7个结点的就是。上图的3号树就是满二叉树。
具有N个结点的完全二叉树其深度为log2^n +1,注意这个特性决定了索引树的时间复杂度。
二叉树的三种遍历
- 前序遍历
根节点(输出自身)→左子树→右子树 - 中序遍历
左子树→根节点(输出自身)→右子树 - 后序遍历
左子树→右子树→根节点(输出自身)
假设有如下的二叉树
中序遍历的具体过程如下
中序遍历:左子树 根节点(输出)右子树
遍历都是从根结点开始:
首先到A,A的左子树存在,找到B。
把B看成子树,找B的左,没有返回B,记录B。
找B右,找到C,又把c看成子树,
找C的左,找到D。记录D,此时D没有了,我
们返回C,再找跟,记录C
入度:为0就是根
出度:为0叶子
BDCAEHGKF
前序遍历为ABCDEFGHK
后序遍历为DCBHKGFEA
具体代码如下
class Node{
private char data;
private Node leftNode;
private Node rightNode;
public Node(char data, Node leftNode, Node rightNode) {
super();
this.setData(data);
this.setLeftNode(leftNode);
this.setRightNode(rightNode);
}
public char getData() {
return data;
}
public void setData(char data) {
this.data = data;
}
public Node getLeftNode() {
return leftNode;
}
public void setLeftNode(Node leftNode) {
this.leftNode = leftNode;
}
public Node getRightNode() {
return rightNode;
}
public void setRightNode(Node rightNode) {
this.rightNode = rightNode;
}
}
public class BinaryTree {
public static void main(String[] args) {
Node D = new Node('D', null, null);
Node H = new Node('H', null, null);
Node K = new Node('K', null, null);
Node C = new Node('C', D, null);
Node B = new Node('B', null, C);
Node G = new Node('G', H, K);
Node F = new Node('F', G, null);
Node E = new Node('E', null, F);
Node A = new Node('A', B, E); //就是root结点
BinaryTree binaryTree = new BinaryTree();
System.out.println("前");
binaryTree.pre(A);
System.out.println("中");
binaryTree.in(A);
System.out.println("后");
binaryTree.post(A);
}
public void print(Node node) {
System.out.print(node.getData());
}
public void pre(Node root) { //前序遍历 根节点 (输出) 左子树 右子树
print(root);
if(root.getLeftNode() != null) {
pre(root.getLeftNode());
}
if(root.getRightNode() != null) {
pre(root.getRightNode());
}
}
public void in(Node root) { //中序遍历 左子树 根节点 (输出) 右子树
if(root.getLeftNode() != null) {
pre(root.getLeftNode());
}
print(root);
if(root.getRightNode() != null) {
pre(root.getRightNode());
}
}
public void post(Node root) { //中序遍历 左子树 右子树 根节点 (输出)
if(root.getLeftNode() != null) {
pre(root.getLeftNode());
}
if(root.getRightNode() != null) {
pre(root.getRightNode());
}
print(root);
}
}
归并排序
归并排序的流程示意图如下,分为分开和合并两个过程。在合并的过程中,只需要对两个数列的头作比较就可以了,因为数列本身就已经时排过序的了,所以整个过程很快速
具体代码如下
public class MergSort {
public static void main(String[] args) {
int data[] = {9,5,6,8,0,3,7,1,20,1};
mergeSort(data, 0, data.length -1);
System.out.println(Arrays.toString(data));
}
public static void mergeSort(int data[],int left,int right) {
if(left < right) {
int mid = (left + right) / 2;
mergeSort(data, left, mid);
mergeSort(data, mid+1, right);
//以上就分完了
merge(data, left, mid, right);
}
}
public static void merge(int data[],int left,int mid,int right) {
int temp[] = new int[data.length]; //就是用来保存合并后的序列,辅助我们排序
int point1 = left; //表示左边的第一个数的位置
int point2 = mid + 1; //表示后边的第一个数的位置
int loc = left; //这个就是用来保存我们当前填了那个数字到temp里面去
while(point1 <= mid && point2 <= right) {
if(data[point1] <= data[point2]) {
temp[loc] = data[point1];
loc ++ ;
point1 ++ ;
}else {
temp[loc] = data[point2];
loc ++ ;
point2 ++ ;
}
}
while(point1 <= mid) {
temp[loc++] = data[point1++];
}
while(point2 <= right) {
temp[loc ++] = data[point2 ++];
}
for(int i = left ;i <= right ; i++) {
data[i] = temp[i];
}
}
}