5.树(上)
0.概念
二叉树
1.二叉树基本操作
1.1 前中后序
/**
* 前中后序遍历:只需改变处理的次序
*/
//从根节点入口时判空
public void preOrder(){
//处理当前节点
System.out.println();
//递归左右子树
if(this.left != null){
this.left.preOrder();
}
if(this.right != null){
this.right.preOrder();
}
}
/**非递归法
* 利用栈实现前序遍历
*/
public ArrayList<Integer> preorderTraversal (TreeNode root) {
ArrayList<Integer> ans = new ArrayList<Integer>();
Stack<TreeNode> st = new Stack<TreeNode>();
if(root == null) return ans;
st.push(root);
while(!st.empty()){
TreeNode t = st.pop();
ans.add(t.val);
//注意入栈次序
if(t.right != null) st.push(t.right);
if(t.left != null) st.push(t.left);
}
return ans;
}
/**
* 利用栈实现中序遍历
*/
public ArrayList<Integer> inorderTraversal (TreeNode root) {
ArrayList<Integer> ans = new ArrayList<Integer>();
Stack<TreeNode> st = new Stack<TreeNode>();
TreeNode p = root;
while(!st.empty() || p != null){
//一直向左到最左边
while(p != null){
st.push(p);
p = p.left;
}
//此时遍历栈顶元素
p = st.pop();
ans.add(p.val);
//并转向其右边,即使为空,在下一轮循环时会转向栈顶
p = p.right;
}
return ans;
}
/**
* 实现非递归后序遍历
*/
1.2 层序遍历
层序遍历二叉树,每一层分别保存
public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) {
ArrayList<ArrayList<Integer>> ans = new ArrayList<ArrayList<Integer>>();
Queue<TreeNode> queue = new LinkedList<TreeNode>();
if (root == null) return ans;
queue.offer(root);
while (!queue.isEmpty()) {
ArrayList<Integer> temp = new ArrayList<Integer>();
int len = queue.size();
for (int i = 0; i < len; i++) {
TreeNode t = queue.peek();
if (t.left != null) {
queue.offer(t.left);
}
if (t.right != null) {
queue.offer(t.right);
}
temp.add(queue.poll().val);
}
ans.add(temp);
}
return ans;
}
1.3 构造二叉树
由中序和另一遍历确定唯一二叉树
/**
* 由中序与前序确定
*/
public TreeNode build(int[] pre,int preBegin,int preEnd,int[] in,int inBegin,int inEnd){
if(preBegin >= preEnd){
return null;
}
TreeNode temp = new TreeNode(pre[preBegin]);
if(preBegin == preEnd - 1) return temp;
int index = 0;
for(int i = inBegin;i < inEnd;i++){
if(temp.val == in[i]){
index = i;
break;
}
}
int len = index - inBegin;
temp.left = build(pre,preBegin+1,preBegin+len+1,in,inBegin,index);
temp.right = build(pre,preBegin+len+1,preEnd,in,index+1,inEnd);
return temp;
}
/**
* 由中序和后序确定,同理
*/
1.4 静态二叉树
public class ArrayTree {
private int[] arr;
public ArrayTree(int[] arr) {
this.arr = arr;
}
public void preOrder(int index) {
if (arr == null || arr.length == 0) {
System.out.println("空树");
}
System.out.println(arr[index]);
//递归遍历
if ((index * 2 + 1) < arr.length) preOrder(2 * index + 1);//左子树
if ((index * 2 + 2) < arr.length) preOrder(2 * index);//右子树
}
}
2.线索二叉树
2.1线索化
public class ThreadedTree {
private TreeNode root;
//保存遍历时前一个节点
private TreeNode pre = null;
//以中序线索为例
public void threadedTree(TreeNode root){
if(root == null) {
return;
}
//左子树
threadedTree(root.left);
//处理当前节点的前驱
if(root.left == null){
root.left = pre;//左为空时,左指向前驱
root.leftType = 1;//修改左指针类型
}
//处理后继节点
if(pre != null && pre.right == null){
pre.right = root;//前驱右指向root
pre.rightType = 1;//修改右指针类型
}
pre = root;//更新前驱
//右子树
threadedTree(root.right);
}
}
3.堆排序
大顶/小顶:每个节点大于等于其子节点
public class HeapSort {
//堆排序
public static void heapSort(int[] arr) {
int temp = 0;
//调整建堆,从下面的非叶节点开始再向上
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i, arr.length);
}
//排序
//每次调整堆(待排序部分)将最大值(根节点)往后插入有序部分
for (int j = arr.length - 1; j > 0; j--) {
temp = arr[j];
arr[j] = arr[0];
arr[0] = temp;
adjustHeap(arr, 0, j);
}
}
/**
* 向下调整:将以i 节点的树调整为大顶堆
*
* @param arr 数组
* @param i 非叶子节点的索引
* @param len 元素数量
*/
public static void adjustHeap(int[] arr, int i, int len) {
int temp = arr[i];//当前元素
//往左子节点
for (int k = i * 2 + 1; k < len; k = 2 * 2 + 1) {
//比较左右子节点,找最大
if (k + 1 < len && arr[k] < arr[k + 1]) {
k++;
}
//子节点大于父
if (arr[k] > temp) {
arr[i] = arr[k];//子往上,i下沉
i = k;
} else {
break;//由于是从下往上开始调整,所以不满足时下面的已调整好
}
}
arr[i] = temp;
}
}
4.霍夫曼树
WPL最小的树:
节点的带权路径长度=路径 X 节点权值
WPL所有叶子节点的带权路径长度之和
节点大的越往上
只有叶节点才放数据
4.1 创建霍夫曼树
class Node implements Comparable<Node> {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
4.2 数据压缩
//通过字符出现的次数为权值,建立节点集,再建立树;
//不同的字符用对应的霍夫曼编码
5.BST
任何非叶子节点左子小于他,右子大于他
中序遍历序列为非减递增
class BNode {
int value;
BNode left;
BNode right;
public BNode(int value) {
this.value = value;
}
//递归添加节点
public void add(BNode node) {
if (node == null) {
return;
}
if (node.value < this.value) {
if (this.left == null) this.left = node;
else this.left.add(node);
} else {
if (this.right == null) this.right = node;
else this.right.add(node);
}
}
//查找节点
public BNode search(int value) {
if (this.value == value) return this;
else if (this.value > value) {
if (this.left == null) return null;
else return this.left.search(value);
} else {
if (this.right == null) return null;
else return this.right.search(value);
}
}
//查找删除节点的父节点
public BNode searchf(int value) {
if ((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)) {
return this;
} else {
if (this.value > value && this.left != null) {
return this.left.searchf(value);
} else if (this.value < value && this.right != null) {
return this.right.searchf(value);
}
return null;
}
}
}
public class BSTree {
private BNode root;
//建树,插入节点
public void add(BNode node) {
if (root == null) {
root = node;
} else root.add(node);
}
//查找节点
public BNode search(int value) {
if (root == null) return null;
else return root.search(value);
}
//查找删除节点的父节点
public BNode searchf(int value) {
if (root == null) {
return null;
} else return root.searchf(value);
}
//删除节点
public void delNode(int value) {
if (root == null) return;
else {
BNode target = search(value);
if (target == null) return;
BNode parent = searchf(value);
//删除叶子节点
if (target.left == null && target.right == null) {
if (parent.left.value == value) {
parent.left = null;
} else {
parent.right = null;
}
} else if (target.left != null && target.right != null) {//删除节点有两个子节点
//删除目标右子树最小的节点并获取此节点
int min = deleteMin(target.right);
//替换目标,即删除了目标节点
target.value = min;
} else {//删除节点有一个子节点
//删除的节点只有左子
if (target.left != null) {
if (parent.left.value == value) {
parent.left = target.left;
} else {
parent.right = target.left;
}
} else {//删除的节点只有右子
if (parent.left.value == value) {
parent.left = target.right;
} else {
parent.right = target.right;
}
}
}
}
}
