数据结构之二叉树

限于喜欢 提交于 2020-03-16 14:57:13

某厂面试归来,发现自己落伍了!>>>

概念:

二叉树是一种特殊的树,其每个节点最多只能有两个子节点。其左子树和右子树是有顺序的,顺序不能颠倒。即使只有一个节点,也要区分左右子树。

斜树:

二叉树中每个节点只有相同方向,全部节点只有左子节点的称为左斜树,只有右子节点的称为右斜树。

满二叉树:

所有的分支节点都具有左子树和右子树,所有的叶子节点都在同一层上,满二叉树追求树的平衡。

满二叉树具备一下特点:

  1. 叶子节点只能出现在最下面一层。
  2. 非叶子节点的度数一定是2。
  3. 在同样深度的二叉树中,满二叉树的节点个数最多,叶子树最多。

完全二叉树:

对一棵具备n个节点的二叉树,对每个节点按照层序编号。如果编号为i的节点,与同样深度的满二叉树编号为i的节点在二叉树的同样位置,那么这棵二叉树就是完全二叉树。满二叉树一定是完全二叉树,完全二叉树不一定树满二叉树。

完全二叉树具备以下性质:

  1. 叶子节点只能出现在最下一层。
  2. 最下层的叶子节点一定出现在左部的连续位置。
  3. 倒数第二层的叶子节点一定出现在右部的连续位置。
  4. 同样节点数的二叉树,完全二叉树的深度最小。

性质:

一般二叉树的性质:

  1. 在非空二叉树的i层上,最多有2^(i-1)个节点。
  2. 在深度为k的二叉树上,最多有2^k-1个节点。
  3. 对于一棵非空的二叉树,如果叶子节点的个数为n0,度数为2的节点的个数为n2,则有n0=n2+1。

在一棵二叉树中,除了叶子节点(n0)之外,就剩下度为2(n2)和度为1(n1)的节点了,则树的节点总数为T=n0+n1+n2;在二叉树中节点总数为T,而连线数为T-1,所以有:n0+n1+n2=2*n2+n1。

完全二叉树的性质:

  1. 具有n个节点的完全二叉树的深度为log2(n)+1。满二叉树是完全二叉树,对于深度为k的满二叉树,其节点个数为2^k-1=n,完全二叉树的节点数量肯定最多2^k-1,同时,完全二叉树倒数第一层有节点时,倒数第二层必定是满的。满二叉树就是完全二叉树的极限情况。因此有2^(k-1)-1<n<=2^k-1,可以推出:2^(k-1)<n<=2^k,即得:k-1<=log2(n)<k。
  2. 如果有一颗有n个节点的完全二叉树的节点按层次序编号,对任一层的节点i(1<=i<=n)有:a、如果i=1,则节点是二叉树的根,无双亲,如果i>1,则亲双亲为(1/2)(向下取整)。b、如果2i>n,则节点i没有左孩子,否则左孩子为2i。c、如果2i+1>n,则节点i没有右孩子,否则右孩子为

遍历:

遍历之前先上一棵模版树:

前序遍历:

思想:先遍历根结点,在前序遍历左子树,在前序遍历右子树。

结果:5248193

public void preOrderTraverse(Node<T> node) {
		if (node != null) {
			System.out.println(node.getValue());
			preOrderTraverse(node.getLeft());
			preOrderTraverse(node.getRight());
		}
    }
}
public void nrPreOrderTraverse() {
		//借助栈实现
		Stack<Node<T>> stack = new Stack<Node<T>>();
		Node<T> node = root;
		
		while (node != null || !stack.isEmpty()) {
			
			while (node != null) {
				System.out.println(node.getValue());
				stack.push(node);
				node = node.getLeft();
			}
			node = stack.pop();
			node = node.getRight();
		}
				
	}
}

中序遍历:

思想:先中序遍历左子树,在访问根结点,在中序遍历右子树。

结果:4821539

public void inOrderTraverse(Node<T> node) {
		if (node != null) {
			inOrderTraverse(node.getLeft());
			System.out.println(node.getValue());
			inOrderTraverse(node.getRight());
		}
	}
}
public void nrInOrderTraverse() {
		
		Stack<Node<T>> stack = new Stack<Node<T>>();
		Node<T> node = root;
		while (node != null || !stack.isEmpty()) {
			while (node != null) {
				stack.push(node);
				node = node.getLeft();
			}
			node = stack.pop();
			System.out.println(node.getValue());
			node = node.getRight();
			
		}
				
	}
}

后序遍历:

思想:先后序遍历左子树,在后序遍历右子树,在访问根结点。

结果:8412395

public void postOrderTraverse(Node<T> node) {
		if (node != null) {
			postOrderTraverse(node.getLeft());
			postOrderTraverse(node.getRight());
			System.out.println(node.getValue());
		}
	}
}
public void nrPostOrderTraverse() {

    Stack<Node<T>> stack = new Stack<Node<T>>();
	Node<T> node = root;
	Node<T> preNode = null;//表示最近一次访问的节点

	while (node != null || !stack.isEmpty()) {
		while (node != null) {
			stack.push(node);
			node = node.getLeft();
		}

		node = stack.peek();

		if (node.getRight() == null || node.getRight() == preNode) {
			System.out.println(node.getValue());
			node = stack.pop();
			preNode = node;
			node = null;
		} else {
			node = node.getRight();
		}
	}
}

层序遍历:

思想:按照层级关系遍历整棵二叉树。

实现方法:可以借助队列实现,将根结点入队列,从队列中弹出元素进行访问,同时将访问的节点的子节点压入队列,不断从队列中弹出元素访问,将子节点压入队列,直到队列中全部访问结束。

结果:5294138

public void levelTraverse(Node<T> node) {
    //借助队列实现
	Queue<Node<T>> queue = new LinkedBlockingQueue<Node<T>>();
	queue.add(node);
	while (!queue.isEmpty()) {

		Node<T> temp = queue.poll();
		if (temp != null) {
			System.out.println(temp.getValue());
			queue.add(temp.getLeft());
			queue.add(temp.getRight());
		}				
	}			
}

其它方法:

获取树的深度:

private Integer getHeight(Node node){
		if(node==null)
			return 0;
		else{
			int left=getHeight(node.getLeft());
			int right=getHeight(node.getRight());
			return left>right?left+1:right+1;//左子树 右子树最深的,再加上父节点本身深度1
		}
	}
}

获取节点数量:

private Integer getSize(Node node){
		if(node==null)
			return 0;
		else{
			int leftSize=getSize(node.getLeft());
			int rightSize=getSize(node.getRight());
			return leftSize+rightSize+1;
		}
	}

}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!