java 3 4_Java-3/4_树.md at master · yrcDream/Java-3 · GitHub
樹
二叉樹
二叉樹具有唯一根節(jié)點(diǎn)
二叉樹每個節(jié)點(diǎn)最多有兩個孩子,最多有一個父親
二叉樹具有天然遞歸結(jié)構(gòu)
二叉樹不一定是 “滿” 的:一個節(jié)點(diǎn)也是二叉樹、空節(jié)點(diǎn)也是二叉樹
二叉搜索樹(BST)
BST 的基本功能
public class BST> {
private Node root;
private int size;
public BST(){
root=null;
size=0;
}
public int size(){
return size;
}
public boolean isEmpty(){
return size==0;
}
private class Node{
public E e;
public Node left,right;
public Node(E e){
this.e=e;
this.left=null;
this.right=null;
}
}
}
添加元素
思路
對于如下的 BST,向其中添加 28:
28 與根結(jié)點(diǎn) 41 比較,應(yīng)該插入左子樹
28 與左子樹的根結(jié)點(diǎn) 22 比較,應(yīng)該插入該結(jié)點(diǎn)的右子樹
28 與 33 比較,應(yīng)該插入該結(jié)點(diǎn)的左子樹,該結(jié)點(diǎn)的左子樹為空,則將值為 28 的結(jié)點(diǎn)添加到該結(jié)點(diǎn)的左子樹中
最終將 28 添加到該 BST 中
代碼
//向BST中添加新元素e
public void add(E e){
if(root==null){
root=new Node(e);
size++;
return;
}else{
add(root,e);
}
}
//向以node為根節(jié)點(diǎn)的BST樹種插入元素e
private void add(Node node,E e){
if(e.equals(node.e)){
//插入元素與根節(jié)點(diǎn)相等,直接返回
return;
}else if(e.compareTo(node.e)<0 && node.left==null){
node.left=new Node(e);
size++;
return;
}else if(e.compareTo(node.e)>0 && node.right==null){
node.right=new Node(e);
size++;
return;
}
if(e.compareTo(node.e)<0){
add(node.left,e);
}else{ //e.compareTo(node.e)>0
add(node.right,e);
}
}
改進(jìn)添加元素
前文中的添加操作,對 root==null 的情況進(jìn)行了特殊處理,并且 add(Node,E) 中的遞歸條件也太冗長了。
這里我們寫一個 add() 方法,返回插入新節(jié)點(diǎn)后該 BST 的根節(jié)點(diǎn)
//向BST中添加新元素e
public void add(E e){
root=add(root,e);
}
//向以node為根節(jié)點(diǎn)的BST樹種插入元素e
//返回插入新元素后該BST的根
private Node add(Node node,E e){
if(node==null){
size++;
return new Node(e);
}
//注意:對于e.equals(node.e)不做處理
if(e.compareTo(node.e)<0){
node.left=add(node.left,e);
}else if(e.compareTo(node.e)>0){
node.right=add(node.right,e);
}
return node;
}
查詢元素
//查看BST中是否包含元素e
public boolean contains(E e){
return contains(root,e);
}
//查看以node為根節(jié)點(diǎn)的BST中是否包含元素e
private boolean contains(Node node,E e){
if(node==null){
return false;
}
if(e.compareTo(node.e)==0){
return true;
}else if(e.compareTo(node.e)<0){
return contains(node.left,e);
}else{
return contains(node.right,e);
}
}
遍歷元素(遞歸形式)
前序遍歷
//BST的前序遍歷
public void preOrder(){
preOrder(root);
}
private void preOrder(Node node){
if(node==null){
return;
}
System.out.println(node.e);
preOrder(node.left);
preOrder(node.right);
}
/**
* 利用前序遍歷打印 BST
*/
@Override
public String toString() {
StringBuilder res=new StringBuilder();
generateBST(root,0,res);
return res.toString();
}
//生成以node為根節(jié)點(diǎn),深度為depth的描述二叉樹的字符串(利用前序遍歷)
private void generateBST(Node node,int depth,StringBuilder res){
if(node==null){
res.append(generateDepth(depth)+"null\n");
return;
}
res.append(generateDepth(depth)+node.e+"\n");
generateBST(node.left,depth+1,res);
generateBST(node.right,depth+1,res);
}
private String generateDepth(int depth){
StringBuilder res=new StringBuilder();
for(int i=0;i
res.append("--");
}
return res.toString();
}
中序遍歷
//BST的中序遍歷
public void inOrder(){
inOrder(root);
}
private void inOrder(Node node){
if(node==null){
return;
}
inOrder(node.left);
System.out.println(node.e);
inOrder(node.right);
}
后序遍歷
//BST的后序遍歷
public void postOrder(){
postOrder(root);
}
private void postOrder(Node node){
if(node==null){
return;
}
postOrder(node.left);
postOrder(node.right);
System.out.println(node.e);
}
遍歷元素(非遞歸形式)
//枚舉命令,GO表示訪問元素,COUT表示打印元素
private enum Command{GO,COUT};
private class StackNode{
Command command;
Node node;
StackNode(Command command,Node node){
this.command=command;
this.node=node;
}
}
前序遍歷
//BST的前序遍歷(非遞歸方式)
public void preOrderNR(){
preOrderNR(root);
}
private void preOrderNR(Node node){
if(node==null){
return;
}
Stack stack=new Stack<>();
stack.push(new StackNode(Command.GO,node));
while(!stack.isEmpty()){
StackNode stackNode=stack.pop();
Node n=stackNode.node;
Command command=stackNode.command;
if(command==Command.COUT){
System.out.println(stackNode.node.e);
}else{
if(n.right!=null){
stack.push(new StackNode(Command.GO,n.right));
}
if(n.left!=null){
stack.push(new StackNode(Command.GO,n.left));
}
stack.push(new StackNode(Command.COUT,n));
}
}
}
中序遍歷
//BST的中序遍歷(非遞歸方式)
public void inOrderNR(){
inOrderNR(root);
}
private void inOrderNR(Node node){
if(node==null){
return;
}
Stack stack=new Stack<>();
stack.push(new StackNode(Command.GO,node));
while(!stack.isEmpty()){
StackNode stackNode=stack.pop();
Node n=stackNode.node;
Command command=stackNode.command;
if(command==Command.COUT){
System.out.println(stackNode.node.e);
}else{
if(n.right!=null){
stack.push(new StackNode(Command.GO,n.right));
}
stack.push(new StackNode(Command.COUT,n));
if(n.left!=null){
stack.push(new StackNode(Command.GO,n.left));
}
}
}
}
后序遍歷
//BST的后序遍歷(非遞歸方式)
public void postOrderNR(){
postOrderNR(root);
}
private void postOrderNR(Node node){
if(node==null){
return;
}
Stack stack=new Stack<>();
stack.push(new StackNode(Command.GO,node));
while(!stack.isEmpty()){
StackNode stackNode=stack.pop();
Node n=stackNode.node;
Command command=stackNode.command;
if(command==Command.COUT){
System.out.println(stackNode.node.e);
}else{
stack.push(new StackNode(Command.COUT,n));
if(n.right!=null){
stack.push(new StackNode(Command.GO,n.right));
}
if(n.left!=null){
stack.push(new StackNode(Command.GO,n.left));
}
}
}
}
層序遍歷
//BST的層序遍歷
public void levelOrder(){
Queue q=new LinkedList<>();
q.add(root);
while(!q.isEmpty()){
Node node=q.remove();
System.out.println(node.e);
if(node.left!=null){
q.add(node.left);
}
if(node.right!=null){
q.add(node.right);
}
}
}
刪除元素
刪除最小值和最大值
尋找 BST 中的最小元素和最大元素
//尋找BST中的最小元素
public E min(){
if(size==0){
throw new IllegalArgumentException("BST is emmpty");
}
return min(root).e;
}
private Node min(Node node){
if(node.left==null){
return node;
}
return min(node.left);
}
//尋找BST中的最大元素
public E max(){
if(size==0){
throw new IllegalArgumentException("BST is emmpty");
}
return max(root).e;
}
private Node max(Node node){
if(node.right==null){
return node;
}
return max(node.right);
}
刪除BST中的最大值和最小值
情況一:最小值是葉子節(jié)點(diǎn)。直接刪除該節(jié)點(diǎn)
情況二:最小值有右子樹。刪除該節(jié)點(diǎn),再將該節(jié)點(diǎn)的右子樹連接到原來的 BST 中
代碼:
//刪除BST中的最小值
public E delMin(){
E res=min();
delMin(root);
return res;
}
//刪除以node為根結(jié)點(diǎn)的BST中的最小值元素
//這里考慮最小值只有右子樹的情況,因?yàn)槿~子節(jié)點(diǎn)是其特例
private Node delMin(Node node){
if(node.left==null){
Node nodeRight=node.right;
node.right=null;
size--;
return nodeRight;
}
node.left=delMin(node.left);
return node;
}
//刪除BST中的最大值
public E delMax(){
E res=max();
delMax(root);
return res;
}
//刪除以node為根結(jié)點(diǎn)的BST中的最大值元素
private Node delMax(Node node){
if(node.right==null){
Node nodeLeft=node.left;
node.left=null;
size--;
return nodeLeft;
}
node.right=delMax(node.right);
return node;
}
刪除任意元素
刪除只有左孩子的節(jié)點(diǎn)。直接刪除即可
刪除只有右孩子的節(jié)點(diǎn)。直接刪除即可
刪除左右孩子都有的節(jié)點(diǎn)
Habbard-Deletion:
d 是待刪除的節(jié)點(diǎn),s 節(jié)點(diǎn)是 d 的后繼,也就是 d 的右子樹的最小值所在的節(jié)點(diǎn)。
注意:這里選擇左子樹的最大值所在的節(jié)點(diǎn)效果也是相同的。
使用 s 代替 d
最后刪除 d 節(jié)點(diǎn)
代碼
//刪除BST中任意元素
public void del(E e){
root=del(root,e);
}
private Node del(Node node,E e){
if(node==null){
return null;
}
if(e.compareTo(node.e)<0){
node.left=del(node.left,e);
return node;
}else if(e.compareTo(node.e)>0){
node.right=del(node.right,e);
return node;
}else{
//節(jié)點(diǎn)node就是要刪除的節(jié)點(diǎn)
//該節(jié)點(diǎn)只右有子樹
if(node.left==null){
Node rightNode=node.right;
node.right=null;
size--;
return rightNode;
}
//該節(jié)點(diǎn)只有左子樹
if(node.right==null){
Node leftNode=node.left;
node.left=null;
size--;
return leftNode;
}
//刪除既有左子樹又有右子樹的節(jié)點(diǎn)
Node s=min(node.right);
s.right=delMin(node.right);
s.left=node.left;
//刪除node
node.left=node.right=null;
return s;
}
}
哈夫曼樹
哈夫曼樹的構(gòu)造過程
首先生成一顆哈夫曼樹,每次生成過程中選取頻率最少的兩個節(jié)點(diǎn),生成一個新節(jié)點(diǎn)作為它們的父節(jié)點(diǎn),并且新節(jié)點(diǎn)的頻率為兩個節(jié)點(diǎn)的和。選取頻率最少的原因是,生成過程使得先選取的節(jié)點(diǎn)位于樹的更低層,那么需要的編碼長度更長,頻率更少可以使得總編碼長度更少。
生成編碼時,從根節(jié)點(diǎn)出發(fā),向左遍歷則添加二進(jìn)制位 0,向右則添加二進(jìn)制位 1,直到遍歷到葉子節(jié)點(diǎn),葉子節(jié)點(diǎn)代表的字符的編碼就是這個路徑編碼。
舉例:
給定了四個結(jié)點(diǎn)a,b,c,d,權(quán)值分別為7,5,2,4。
找出現(xiàn)有權(quán)值中最小的兩個,2 和 4 ,相應(yīng)的結(jié)點(diǎn) c 和 d 構(gòu)建一個新的二叉樹,樹根的權(quán)值為 2 + 4 = 6,同時將原有權(quán)值中的 2 和 4 刪掉,將新的權(quán)值 6 加入。
重復(fù)之前的步驟。
所有的結(jié)點(diǎn)構(gòu)建成了一個全新的二叉樹,這就是哈夫曼樹。
代碼
public class Huffman {
private class Node implements Comparable {
char ch;
int freq;
boolean isLeaf;
Node left, right;
public Node(char ch, int freq) {
this.ch = ch;
this.freq = freq;
isLeaf = true;
}
public Node(Node left, Node right, int freq) {
this.left = left;
this.right = right;
this.freq = freq;
isLeaf = false;
}
@Override
public int compareTo(Node o) {
return this.freq - o.freq;
}
}
public Map encode(Map frequencyForChar) {
PriorityQueue priorityQueue = new PriorityQueue<>();
for (Character c : frequencyForChar.keySet()) {
priorityQueue.add(new Node(c, frequencyForChar.get(c)));
}
while (priorityQueue.size() != 1) {
Node node1 = priorityQueue.poll();
Node node2 = priorityQueue.poll();
priorityQueue.add(new Node(node1, node2, node1.freq + node2.freq));
}
return encode(priorityQueue.poll());
}
private Map encode(Node root) {
Map encodingForChar = new HashMap<>();
encode(root, "", encodingForChar);
return encodingForChar;
}
private void encode(Node node, String encoding, Map encodingForChar) {
if (node.isLeaf) {
encodingForChar.put(node.ch, encoding);
return;
}
encode(node.left, encoding + '0', encodingForChar);
encode(node.right, encoding + '1', encodingForChar);
}
}
總結(jié)
以上是生活随笔為你收集整理的java 3 4_Java-3/4_树.md at master · yrcDream/Java-3 · GitHub的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html em vw,CSS3 的视口单
- 下一篇: 未来教育计算机二级为什么分数很低,计算机