数据结构-树
基础知识
树是一个有n个有限节点组成一个具有层次关系的集合,每个节点有0个或多个子节点,没有父节点的节点称为根节点,也就是说除了根节点以外每个节点都有父节点,并且有且仅有一个。
树的种类比较多,有二叉树,红黑树,AVL树,B树,哈夫曼树,字典树等等。
定义(名词含义)
- **结点的度:**一个节点含有的子节点的个数称为该结点的度;
- **叶节点或终端结点:**度为0的节点称为节结点;
- **非终端结点或分支节点:**度不为0的节点;
- **双亲节点或父节点:**若一个结点含有子节点,则这个节点称为该子结点的父节点;
- **孩子结点或子结点:**一个结点含有的子树的根结点称为该结点的子结点;
- **兄弟结点:**具有相同父节点的节点互称为兄弟结点;
- **树的度:**一颗树中,最大的节点的度称为树的度;
- **结点的层次:**从跟开始定义起,跟为第1层,根的子结点为第2层,以此类推;
- **树的高度或深度:**树中结点的最大层次;
- **堂兄弟节点:**双亲在同一层的结点互为堂兄弟;
- **结点的祖先:**从根到该结点所经分支上的所有节点;
- **子孙:**以某结点为根的子树中任一结点都称为该结点的子孙;
- **森林:**由m(m>=0)颗互不相交的树的集合称为森林;
- **无序树:**树中任意结点的子结点之间没有顺序关系,这种树称为无序树,也称为自由树;
- **有序树:**树中任意结点的子结点之间有顺序关系,这种树称为有序树;
- **二叉树:**每个节点最多含有两个子树的树称为二叉树;
- **完全二叉树:**若设二叉树的深度为h,除第h层外,其它各层(1~h-1)的结点数都达到最大个数,第h层所有的结点都连续集中在最左边,这就是完全二叉树;
- **满二叉树:**除最后一层无任何子结点外,每一层上的所有结点都有两个子结点的二叉树;
- **哈夫曼树:**带权路径最短的二叉树称为哈夫曼树或最优二叉树;
应用
节点类(二叉树)
public class TreeNode {
public String val;
public TreeNode left;
public TreeNode right;
public TreeNode() {
}
public TreeNode(String val) {
this.val = val;
}
@Override
public String toString() {
return "[" +
"val=" + val +
']';
}
}
前序遍历
访问顺序:根节点—>左子树—>右子树
遍历结果为:A->B->D->E->C->F
访问顺序如下:
代码如下
public static void proOrder(TreeNode tree){
if (tree == null)
return;
System.out.println(tree);
proOrder(tree.left);
proOrder(tree.right);
}
非递归方式
public static void proOrder2(TreeNode tree){
if (tree == null)
return;
Stack<TreeNode> stack = new Stack<>();
stack.push(tree);
while (!stack.isEmpty()){
TreeNode pop = stack.pop();
System.out.println(pop.val);
if (pop.right != null)
stack.push(pop.right);
if (pop.left != null)
stack.push(pop.left);
}
}
中序遍历
访问顺序:左子树—>根节点—>右子树
遍历结果为:D->B->E->A->F->C
访问顺序如下:
代码如下
public static void inOrderTraversal(TreeNode tree){
if (tree == null)
return;
inOrderTraversal(tree.left);
System.out.println(tree.val);
inOrderTraversal(tree.right);
}
非递归方式
public static void inOrderTraversal2(TreeNode tree){
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || tree != null){
while (tree != null){
stack.push(tree);
tree = tree.left;
}
if (!stack.isEmpty()){
tree = stack.pop();
System.out.println(tree.val);
tree = tree.right;
}
}
}
后序遍历
访问顺序:左子树—>右子树—>根节点
遍历结果为:D->E->B->F->C->A
访问顺序如下:
代码如下:
public static void postOrder(TreeNode tree){
if (tree == null)
return;
postOrder(tree.left);
postOrder(tree.right);
System.out.println(tree.val);
}
非递归方式
public static void postOrder2(TreeNode tree){
if (tree == null)
return;
Stack<TreeNode> s1 = new Stack<>();
Stack<TreeNode> s2 = new Stack<>();
s1.push(tree);
while (!s1.isEmpty()){
tree = s1.pop();
s2.push(tree);
if (tree.left != null)
s1.push(tree.left);
if (tree.right != null)
s1.push(tree.right);
}
while (!s2.isEmpty()){
System.out.println(s2.pop().val);
}
}
BFS(宽度优先搜索,又称广度优先搜索)
访问顺序:先访问上一层,再访问下一层,一层一层往下访问
遍历结果为:A->B->C->D->E->F
访问顺序如下:
代码如下:
public static void levelOrder2(TreeNode tree){
int depth = depth(tree);
for (int level = 0; level < depth; level++) {
printLevel(tree, level);
}
}
//获得当前树的层数
public static int depth(TreeNode tree){
if (tree == null)
return 0;
int leftDepth = depth(tree.left);
int rightDepth = depth(tree.right);
return Math.max(leftDepth, rightDepth) + 1;
}
//获取指定层数的数据
public static void printLevel(TreeNode tree, int level){
if (tree == null)
return;
if (level == 0){
System.out.println(tree.val);
}else {
printLevel(tree.left, level -1);
printLevel(tree.right, level -1);
}
}
非递归方式
public static void levelOrder(TreeNode tree){
if (tree == null)
return;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(tree);
while (!queue.isEmpty()){
tree = queue.poll();
System.out.println(tree.val);
if (tree.left != null)
queue.add(tree.left);
if (tree.right != null)
queue.add(tree.right);
}
}
DFS(深度优先搜索)
访问顺序:先访问根节点,然后左节点,一直往下,知道没有左节点,往上退一步到父节点,然后父节点的右节点,再重复上面步骤
遍历结果为:A->B->->D->E->C->F
访问顺序如下:
代码如下:
public static void treeDFS2(TreeNode tree){
if (tree == null)
return;
System.out.println(tree.val);
treeDFS2(tree.left);
treeDFS2(tree.right);
}
非递归方式
public static void treeDFS(TreeNode tree){
if (tree == null)
return;
Stack<TreeNode> stack = new Stack<>();
stack.push(tree);
while (!stack.isEmpty()){
tree = stack.pop();
System.out.println(tree.val);
if (tree.right != null)
stack.push(tree.right);
if (tree.left != null)
stack.push(tree.left);
}
}
遍历并将结果放入list中
public static List<List<String>> levelOrder3(TreeNode tree){
List<List<String>> lists = new ArrayList<>();
if (tree == null)
return lists;
bfs(lists, tree, 0);
return lists;
}
public static void bfs(List<List<String>> lists, TreeNode tree, int level){
if (tree == null)
return;
//level表示的是层数,如果level>=list.size(),说明到下一层了,所以要先把下一次的list初始化,防止add时出现空指针异常
if (level >= lists.size())
lists.add(new ArrayList<>());
//level表示的是第几层,这里访问到第几层,我们就把数据加入到第几层
lists.get(level).add(tree.val);
//当前节点访问完之后,再使用递归的方式分别访问当前节点的左右子节点
bfs(lists, tree.left, level + 1);
bfs(lists, tree.right, level + 1);
}
非递归方式
public static List<List<String>> levelOrder4(TreeNode tree){
List<List<String>> lists = new ArrayList<>();
if (tree == null)
return lists;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(tree);
while (!queue.isEmpty()){
int size = queue.size();
List<String> list = new ArrayList<>();
while (size-- > 0){
tree = queue.poll();
list.add(tree.val);
if (tree.left != null)
queue.add(tree.left);
if (tree.right != null)
queue.add(tree.right);
}
lists.add(list);
}
return lists;
}