王学岗数据结构和算法

第一节课,数据结构与算法入门和线性表顺序存储结构

1,ab的值交换

        int a = 5;
        int b = 6;
        a = a ^ b;
        b = a ^ b;
        a = a ^ b;

2,冒泡排序

 public static void bubbleSort(int[] array){
        //3 1 5 8 2 9 4 6 7    n*(n-1)/2    n
        for(int i=array.length-1;i>0;i--) {
            boolean flag=true;
            for (int j = 0; j < i; j++) {
                if (array[j] > array[j + 1]) {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                    flag=false;
                }
            }
            if(flag){
                break;
            }
        }
    }

3,选择排序
先假定第一个是最小的,然后其余每个元素和第一个元素比较。

  public static void selectSort(int[] array){
        for(int i=0;i<array.length-1;i++) {
            int index = i;
            for (int j = i+1; j < array.length; j++) {
                if (array[j] < array[index]) {
                    index = j;
                }
            }
            //{1,2,5,8,3,9,4,6,7};
            if(index!=i) {//如果已经是最小的,就不需要交换
                int temp = array[index];
                array[index] = array[i];
                array[i] = temp;
            }
        }
    }

第二节课线性表的链式存储结构

1,>>与<<算法
左移右移动是二进制乘除过程,往右边移动数据是几就是除以2的几次方,往左边移动就是乘以2的几次方。
2,messageQueue就是一个线性表链式存储结构
3,麻将排序
在这里插入图片描述
看下代码是如何实现的,先看下麻将类

package com.example.jett.lsn_2_20181128;

/**
 * Created by 48608 on 2017/12/6.
 */

public class Mahjong {
    public int suit;//筒,万,索
    public int rank;//点数 一  二  三

    public Mahjong(int suit, int rank) {
        this.suit = suit;
        this.rank = rank;
    }

    @Override
    public String toString() {
        return "("+this.suit+" "+this.rank+")";
    }
}

排序类

package com.example.jett.lsn_2_20181128;

import org.junit.Test;

import java.util.LinkedList;

/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() throws Exception {
        LinkedList<Mahjong> list=new LinkedList<Mahjong>();
        list.add(new Mahjong(3,1));
        list.add(new Mahjong(2,3));
        list.add(new Mahjong(3,7));
        list.add(new Mahjong(1,1));
        list.add(new Mahjong(3,8));
        list.add(new Mahjong(2,2));
        list.add(new Mahjong(3,2));
        list.add(new Mahjong(1,3));
        list.add(new Mahjong(3,9));
        System.out.println(list);
        radixSort(list);
        System.out.println(list);
    }
    public static void radixSort(LinkedList<Mahjong> list){
        //先对点数进行分组,创建一个LinkedList数组,里面有9个元素
        LinkedList[] rankList=new LinkedList[9];
        for (int i = 0; i < rankList.length; i++) {
            rankList[i]=new LinkedList();
        }
        //把数据一个个放到对应的组中
        while(list.size()>0){
            //取一个
            Mahjong m=list.remove();
            //放到组中  下标=点数减1的
            rankList[m.rank-1].add(m);
        }
        //把9组合并在一起
        for (int i = 0; i < rankList.length; i++) {
            list.addAll(rankList[i]);
        }




        //先花色进行分组
        LinkedList[] suitList=new LinkedList[3];
        for (int i = 0; i < suitList.length; i++) {
            suitList[i]=new LinkedList();
        }

        //把数据一个个放到对应的组中
        while(list.size()>0){
            //取一个
            Mahjong m=list.remove();
            //放到组中  下标=点数减1的
            suitList[m.suit-1].add(m);
        }
        //把3个组合到一起
        for (int i = 0; i < suitList.length; i++) {
            list.addAll(suitList[i]);
        }
    }
}

4,手动实现双向链表结构

package com.example.jett.lsn_2_20181128.test_linkedlist;

/**
 * Created by Jett on 2018/11/28.
 */

public class LinkedList<E> {
    /**
     * 结点
     */
    private static class Node<E> {
        E item;
        Node<E> prev;
        Node<E> next;

        public Node(Node<E> prev, E item, Node<E> next) {
            this.item = item;
            this.prev = prev;
            this.next = next;
        }
    }

    public LinkedList() {

    }
    
    //头节点
    Node<E> first;
    //尾节点
    Node<E> last;
    //大小
    int size;

    /**
     * 添加数据在最后
     */
    public void add(E e) {
        linkLast(e);
    }

    /**
     * 添加到最后,尾部添加,上一个节点肯定是最后一个
     * @param e
     */
    private void linkLast(E e) {
		//new 的时候就定了前驱是last
        Node<E> newNode = new Node<E>(last, e, null);
		//拿到新节点把尾巴先保存起来
        Node<E> l = last;
		//last指针赋值为新的节点
        last=newNode;
        
        if(l==null){
            first=newNode;
        }else {
			//
            l.next = newNode;
        }
        size++;
    }
    /**
     * 查找位置
     */
    public E get(int index){
        if(index<0 || index>size){
            return null;
        }
        return node(index).item;
    }
    /**
     * 获取index位置上的节点
     */
    private Node<E> node(int index){

        //如果index在整个链表的前半部分,这是双向链表优于单向链表的地方
        if(index<(size>>1)){   //除以2的一次方
            Node<E> node=first;
            for (int i = 0; i < index; i++) {
				//往后移动一位
                node=node.next;
            }
            return node;
        }else{
            Node<E> node=last;
            for (int i = size-1; i > index; i--) {
                node=node.prev;
            }
            return node;
        }


    }

    /**
     * 添加数据在index位置
     */
    public void add(int index,E e) {
        if(index<0 || index>size){
            return ;
        }
        if(index==size){
			//添加到尾部
            linkLast(e);
        }else{
            Node<E> target=node(index);//  index=2
			//前面的节点
            Node<E> pre=target.prev;
			//开启一个新的节点,此时该节点已经指向了前一个节点和后一个节点
            Node<E> newNode=new Node<E>(pre,e,target);

            if(pre==null){
                first=newNode;
                target.prev = newNode;//4
            }else {
                pre.next = newNode;//3
                target.prev = newNode;//4
            }
            size++;
        }

    }

    /**
     * 删除元素
     */
    public void remove(int index){
        Node<E> target=node(index);
        unlinkNode(target);
    }

    private void unlinkNode(Node<E> p) {//index=2
        Node<E> pre=p.prev;
        Node<E> next=p.next;
		
        if(pre==null){
			//是第一节点
            first=p.next;
        }else{
            pre.next=p.next;
        }
		//是最后一个节点
        if(next==null){
            last=p.prev;
        }else{
            next.prev=p.prev;
        }
        size--;
    }

}

第三节课,栈与栈的应用

1,跟顺序存储结构、链式存储结构一样,栈也是一种线性表。允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出的线性表.
栈有两种实现方式,顺序方式和链式方式,。
2,android中Stack类就是一个顺序方式实现的栈。Stack空间不够的时候会自动扩大到原来的两倍,这一点和ArrayList(每次扩大1.5倍)很像。当需要删除栈顶的数据时候,Stack会直接令栈顶元素=null。
在这里插入图片描述
3,链式进栈出栈的操作
入栈
在这里插入图片描述
4,a/2,a*2的性能不如a>>2和a<<a,为什么呢?
在c/c++/java中,后者只需要一个指令集,前者需要6个指令集以上。
高级语言计算的时候用的是逆波兰表达式
比如9+(3-1)X3+10/2 20
在这里插入图片描述
5,递归
程序调用自身的编程技巧称为递归(recursion)。
递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,
它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,
递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的能力在于用有限的语句来定义对象的无限集合。
一般来说,递归需要有边界条件、递归前进段和递归返回段。
当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
5.1看一个简单的递归,

public void fun(int n){  //3
        System.out.println(n);
        if(n<0){
            return;
        }else{
            fun(n-1);
            System.out.println(n);
        }
    }
3
2
1
0
-1
0
1
2
3

解析图
f(n-1)之前的代码是顺向执行的,f(n-1)之后的代码是反向执行的。程序会将f(n-1)之后的代码压入一个栈。当return之后,会顺序执行栈内的代码。每执行一次f(n-1),程序就会将 System.out.println(n);这段代码压入栈中。当n=321时候, System.out.println(n);会被依次压入一个栈。
5.2我们现在有一个阶乘的公式,1234……n;
我们发现 5!=5
4!, 4!=4
3!。这种情况下就可以使用递归。

 public int fact(int n){
        if(n==1){
            return 1;
        }else{
            return n*fact(n-1);
        }
    }

5.3斐波那契数列(Fibonacci sequence)
1 1 2 3 5 8 13 21 34 55 89 144…

 public int fibonacciSequence(int n){
        if(n==1 || n==2){
            return 1;
        }else{
            return fibonacciSequence(n-1)+fibonacciSequence(n-2);
        }
    }

我们看下图解析,你会发现递归和树有很大的联系
在这里插入图片描述
5.4汉诺塔问题

 /**
     * @param n      盘子的个数
     * @param start   开始的柱子
     * @param middle   中介柱子
     * @param end      结果柱子
     */
    public static void hanoi(int n,int start,int middle,int end){
        if(n<=1){
            System.out.println(start+"----->"+end);
        }else{
            hanoi(n-1,start,end,middle);
            System.out.println(start+"----->"+end);
            hanoi(n-1,middle,start,end);
        }
    }

第四节课,哈希表与树的入门

1,哈希表,也叫散列表,是根据关键码值(Key value)而直接进行访问的数据结构,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。
哈希表综合了数组和链表的特性
数组(顺序表):寻址容易
链表:插入与删除容易
哈希表:寻址容易,插入删除也容易的数据结构
2,二叉树的遍历
在这里插入图片描述
我们创建并遍历二叉树

package com.example.jett.lsn_4_20181203;

/**
 * Created by Jett on 2018/12/3.
 */

public class BinarayTree {
    Node<String> root;//根节点
    public BinarayTree(String data){
		//构造方法创建根节点
        root=new Node<>(data,null,null);
    }
    public void createTree(){
        Node<String> nodeB=new Node<String>("B",null,null);
        Node<String> nodeC=new Node<String>("C",null,null);
        Node<String> nodeD=new Node<String>("D",null,null);
        Node<String> nodeE=new Node<String>("E",null,null);
        Node<String> nodeF=new Node<String>("F",null,null);
        Node<String> nodeG=new Node<String>("G",null,null);
        Node<String> nodeH=new Node<String>("H",null,null);
        Node<String> nodeJ=new Node<String>("J",null,null);
        Node<String> nodeI=new Node<String>("I",null,null);
        root.leftChild=nodeB;
        root.rightChild=nodeC;
        nodeB.leftChild=nodeD;
        nodeC.leftChild=nodeE;
        nodeC.rightChild=nodeF;
        nodeD.leftChild=nodeG;
        nodeD.rightChild=nodeH;
        nodeE.rightChild=nodeJ;
        nodeH.leftChild=nodeI;

    }

    /**
     * 中序访问树的所有节点LDR
     */
    public void midOrderTraverse(Node root){//逻辑
        if(root==null){
            return;
        }
        midOrderTraverse(root.leftChild);//逻辑
        System.out.println("mid:"+root.data);//输出
        midOrderTraverse(root.rightChild);//逻辑
    }
    /**
     * 前序访问树的所有节点  Arrays.sort(); DLR
     */
    public void preOrderTraverse(Node root){
        if(root==null){
            return;
        }
        System.out.println("pre:"+root.data);
        preOrderTraverse(root.leftChild);
        preOrderTraverse(root.rightChild);
    }
    /**
     * 后序访问树的所有节点LRD
     */
    public void postOrderTraverse(Node root){
        if(root==null){
            return;
        }
        postOrderTraverse(root.leftChild);
        postOrderTraverse(root.rightChild);
        System.out.println("post:"+root.data);
    }






    /**
     * 节点
     */
    public class Node<T>{
        T data;//存数据
        Node<T> leftChild;
        Node<T> rightChild;

        public Node(T data, Node<T> leftChild, Node<T> rightChild) {
            this.data = data;
            this.leftChild = leftChild;
            this.rightChild = rightChild;
        }
    }

}


测试方法

   BinarayTree binarayTree=new BinarayTree("A");
        binarayTree.createTree();
        binarayTree.midOrderTraverse(binarayTree.root);
        binarayTree.preOrderTraverse(binarayTree.root);
        binarayTree.postOrderTraverse(binarayTree.root);

3,二叉树的查找
顺序查找法,比如有一个int类型数组,我们要查找15所在的位置,我们可以依次把数组中的元素取出来和15比较,如果取出的元素等于15,那么就返回该元素在数组的位置,就是15在数组中的位置
二分查找法,如果数据已经排好序了,可以使用二分查找法。
二分查找法的代码

  /**
     * 二分查找
     */
    public static int binarySearch(int[] array,int fromIndex,int toIndex,int key){
        int low=fromIndex;
        int high=toIndex-1;//因为是左闭右开,所以要-1
        while(low<=high){
            int mid=(low+high)/2;//取中间
            int midVal=array[mid];
            if(key>midVal){//去右边找
                low=mid+1;
            }else if(key<midVal){//去左边找
                high=mid-1;
            }else{
                return mid;
            }
        }
        return -(low+1);//low+1表示找不到时停在了第low+1个元素的位置
    }

调用

int[] array=new int[]{1,2,4,9,31,266,656,56666,888888};
int key=31;
binarySearch(array,0,array.length,key)

4,混乱数据的排序的方法————快速排序法
Java Arrays.sort()使用的就是快速排序法

 //快速排序     31  21  59  68  12  40
    //    x=31
    public static void quickSort(int[] array,int begin,int end){
        if(end-begin<=0) return;
        int x=array[begin];
        int low=begin;//0
        int high=end;//5
        //由于会从两头取数据,一会左边,一会右边,需要一个变量控制方向
        boolean direction=true;
        L1:
        while(low<high){
            if(direction){//从右往左找
                for(int i=high;i>low;i--){
                    if(array[i]<=x){
                        //array[low++]=array[i];
						array[low]=array[i]
						low++;
                        high=i;
                        direction=!direction;
                        continue L1;
                    }
                }
                high=low;//如果上面的if从未进入,让两个指针重合
            }else{
                for(int i=low;i<high;i++){
                    if(array[i]>=x){
                       // array[high--]=array[i];
                        array[high]=array[i];
                        high--
                        low=i;
                        direction=!direction;
                        continue L1;
                    }
                }
                low=high;
            }
        }
        //把最后找到的值 放入中间位置
        array[low]=x;
        //开始完成左右两边的操作
        quickSort(array,begin,low-1);
        quickSort(array,low+1,end);
    }

时间复杂度n*log2^n;
快速排序法的缺点:(1)含有大量重复元素的时候性能下降;(2)不适合链式线性表.
5,归并排序法:
弥补了快速排序法的缺点

 public static void mergeSort(int array[],int left,int right){
        if(left==right){
            return;
        }else{
            int mid=(left+right)/2;
            mergeSort(array,left,mid);
            mergeSort(array,mid+1,right);
            merge(array,left,mid+1,right);
        }
    }

    //    0    4   7
    //    1  2  5  9 === 3  4  10  11
    public static void merge(int[] array,int left,int mid,int right){
        int leftSize=mid-left;
        int rightSize=right-mid+1;
        //生成数组
        int[] leftArray=new int[leftSize];
        int[] rightArray=new int[rightSize];
        //填充数据
        for(int i=left;i<mid;i++){
            leftArray[i-left]=array[i];
        }
        for(int i=mid;i<=right;i++){
            rightArray[i-mid]=array[i];
        }
        //合并
        int i=0;
        int j=0;
        int k=left;
        while(i<leftSize && j<rightSize){
            if(leftArray[i]<rightArray[j]){
                array[k]=leftArray[i];
                k++;i++;
            }else{
                array[k]=rightArray[j];
                k++;j++;
            }
        }
        while(i<leftSize){
            array[k]=leftArray[i];
            k++;i++;
        }
        while(j<rightSize){
            array[k]=rightArray[j];
            k++;j++;
        }
    }

因为创建了大量的数组,所以归并排序对空间需求大 ,是以空间换时间
时间复杂度n*log2^n;

第六节课,二叉排序树

1,二叉排序树的生成
在这里插入图片描述
根节点为5,然后2和5比较,2比5小放左边,7比5大放右边,3和5比较,比5小在和右边的2比较,比2大放到2的右边……以此类推

下面我手动实现一颗树

package com.example.jett.lsn_6_20181207;

import java.util.NoSuchElementException;

/**
 * Created by Jett on 2018/12/7.
 */

public class SearchBinaryTree {
    //根节点
    public TreeNode root;

    /**
     * 添加节点
     */
    public TreeNode put(int data){
		//如果是空树,就把data只作为根节点
        if(root==null){
            TreeNode node=new TreeNode(data);
            root=node;
            return node;
        }
        TreeNode parent=null;
		//拿到根节点
        TreeNode node=root;
        //找到要放入的位置
        while(node!=null){
            parent=node;//循环跑完,node可定为空,我们需要记录parent,根据parent找到该node的位置
            if(data<node.data){
                node=node.leftChild;
            }else if(data>node.data){//如果允许放入重复值,这里可以改为>=
                node=node.rightChild;
            }else{//是重复值 就不理会了,不允许存放重复值
                return node;
            }
        }
        //根据数据域data生成一个节点,放入
        TreeNode newNode=new TreeNode(data);
        if(data<parent.data) {
            parent.leftChild = newNode;
        }else{
            parent.rightChild=newNode;
        }
        newNode.parent=parent;

        return newNode;
    }


    /**
     * 中序遍历
     */
    public void midOrderTraverse(TreeNode root){
        if(root==null){
            return;
        }
        //LDR
        midOrderTraverse(root.leftChild);
        System.out.print(root.data+" ");
        midOrderTraverse(root.rightChild);
    }

    /**
     * 查找一个节点,小往左边走,大往右边走;
	 * 如果传入的数据树里没有,会返回null,报空指针异常,需要自己在程序中控制
     */
    public TreeNode searchNode(int data){
        if(root==null){
            return null;
        }
        TreeNode node=root;//记录下节点,可以理解为指针
        while(node!=null){
            if(node.data==data){
                return node;
            }else if(data>node.data){
                node=node.rightChild;
            }else if(data<node.data){
                node=node.leftChild;
            }
        }
        return null;
    }


    /**
     * 删除节点
     * 要删除的节点在树上是一定存在的才删除
	 * 删除的节点有下面几种情况
	 * 1,节点是叶子
	 * 2,只有左孩子
	 * 3,只有右孩子
	 * 4,左右孩子都有
     */
    public void delNode(TreeNode node){
        if(node==null){
            throw new NoSuchElementException();
        }else{
            //先得到父亲,方便后面的操作
            TreeNode parent=node.parent;
            //1.叶子
            if(node.leftChild==null && node.rightChild==null){
                //特别的情况:1.树上只有一个节点或是空树
                if(parent==null){//没有父亲,说明是根节点
                    root=null;
                }else if(parent.rightChild==node){
                    parent.rightChild=null;
                }else if(parent.leftChild==node){
                    parent.leftChild=null;
                }
                node.parent=null;//双向链表,两个都要为空
            }else if(node.leftChild!=null && node.rightChild==null){
                //2.只有左孩子
                if(parent==null){//如果要删除的是根
                    node.parent=null;
                    node.leftChild.parent=null;
                    root=node.leftChild;
                }else{
                    if(parent.leftChild==node){//要删除的节点是父亲的左边
                        node.leftChild.parent=parent;//双链表结构,有两个指针,父亲指向孩子的指针,孩子指向父亲的指针。
                        parent.leftChild=node.leftChild;

                    }else{//要删除的节点是父亲的右边
                        node.leftChild.parent=parent;
                        parent.rightChild=node.leftChild;
                    }
                    node.parent=null;
                }

            }else if(node.leftChild==null && node.rightChild!=null){
                //3.只有右孩子
                if(parent==null){//如果要删除的是根
                    node.parent=null;
                    node.rightChild.parent=null;
                    root=node.rightChild;
                }else{
                    if(parent.leftChild==node){//要删除的节点是父亲的左边
                        node.rightChild.parent=parent;
                        parent.leftChild=node.rightChild;
                    }else{//要删除的节点是父亲的右边
                        node.rightChild.parent=parent;
                        parent.rightChild=node.rightChild;
                    }
                    node.parent=null;
                }
            }else{//4。有左右两个孩子
                if(node.rightChild.leftChild==null){//1.如果被删除节点的右子树的左子树为空,就直接补上右子树
                    node.rightChild.leftChild=node.leftChild;
                    if(parent==null){//如果是根节点
                        root=node.rightChild;
                    }else{
                        if(parent.leftChild==node){
                            parent.leftChild=node.rightChild;
                            //
                        }else{
                            parent.rightChild=node.rightChild;
                            //
                        }
                    }
                    node.parent=null;
                }else{//2.否则就要补上右子树的左子树上最小的一个
                    TreeNode leftNode=getMinLeftTreeNode(node.rightChild);
                    //1   注:这四个步骤我下面画了张图,可以作为参考
                    //父引用我没断开,自己手动断开
                    leftNode.leftChild=node.leftChild;
                    //2
                    TreeNode leftNodeP=leftNode.parent;
                    leftNodeP.leftChild=leftNode.rightChild;
                    //3
                    leftNode.rightChild=node.rightChild;
                    //4
                    if(parent==null){//如果是跟节点
                        root=leftNode;
                    }else{
                        if(parent.leftChild==node){
                            parent.leftChild=leftNode;
                            //
                        }else{
                            parent.rightChild=leftNode;
                            //
                        }
                    }
                }
            }
        }
    }
//寻找左边孩子的左边孩子的左边孩子……即最小的那个
    private TreeNode getMinLeftTreeNode(TreeNode node) {
        TreeNode curRoot=null;
        if(node==null){
            return null;
        }else{
            curRoot=node;
            while(curRoot.leftChild!=null){
                curRoot=curRoot.leftChild;
            }
        }
        return curRoot;
    }


    public static class TreeNode{
        int  data;//实际开发中用的可能是泛型T data
        TreeNode leftChild;
        TreeNode rightChild;
        TreeNode parent;
        public TreeNode(int data){
            this.data=data;
            this.leftChild=null;
            this.rightChild=null;
            this.parent=null;
        }
    }
}

在这里插入图片描述

第七节课,启发式寻路

第八节课,halfman树与AVL树

1,假设我们有n个学生,5%不及格,60-69占15%,80-90占30%,90-100占10%;
有如下代码

if(a<60){
System.out.println("不及格");
}else if(a<70){
System.out.println("……");
}else if(a<80){
}else if(a<90){
}else{
}

假设我们现在有100个学生
那么条件语句执行的次数为
51+152+403+304+10*5=325;
这个算法并不是很好
我们现在修改下使他变得更优秀。

if(a<80){}else if(a<90{})else if(a<100){}else if(a<70)else{}

如果这样计算,条件语句执行的次数就是
401+302+153+104+5*5=210
这样性能就得到了提升,这是一个标准的压缩启蒙思想。

huffman树就是这样的一种树
下面我们手动创建一个huffman树

package com.example.jett.lsn_8_20181214;

import android.support.annotation.NonNull;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Stack;

/**
 * Created by Jett on 2018/12/14.
 */

public class HuffmanTree {
    TreeNode root;

    public TreeNode createHuffManTree(ArrayList<TreeNode> list) {
        while (list.size() > 1) {
            Collections.sort(list);//从小到大排序
            TreeNode left = list.get(list.size() - 1);
            TreeNode right = list.get(list.size() - 2);
            TreeNode parent = new TreeNode("p", left.weight + right.weight);
            parent.leftChild = left;
            left.parent = parent;
            parent.rightChild = right;
            right.parent = parent;
            list.remove(left);
            list.remove(right);
            list.add(parent);
        }
        root = list.get(0);
        return list.get(0);
    }
  //这里不能用前中后序法遍历,我们要一行一行的把数据打印输出
    public void showHuffman(TreeNode root) {
        LinkedList<TreeNode> list = new LinkedList<>();
        list.offer(root);//入队
        while (!list.isEmpty()) {
            TreeNode node = list.pop();
            System.out.println(node.data);
            if (node.leftChild != null) {
                list.offer(node.leftChild);
            }
            if (node.rightChild != null) {
                list.offer(node.rightChild);
            }
        }
    }

    @Test
    public void test() {
        ArrayList<TreeNode> list = new ArrayList<>();
        TreeNode<String> node = new TreeNode("good", 50);
        list.add(node);
        list.add(new TreeNode("morning", 10));//前面是符号,后面是出现的次数
        TreeNode<String> node2 =new TreeNode("afternoon", 20);
        list.add(node2);
        list.add(new TreeNode("hell", 110));
        list.add(new TreeNode("hi", 200));
        HuffmanTree tree = new HuffmanTree();
        tree.createHuffManTree(list);
        tree.showHuffman(tree.root);
        getCode(node2);
    }

    /**
     * 编码,左边是0,右边是1
     */
    public void getCode(TreeNode node) {
        TreeNode tNode = node;
		//我们从底部找起,但是编码要从上部算起,所以我们用栈,先进后出。
        Stack<String> stack = new Stack<>();
        while (tNode != null && tNode.parent != null) {
            //left 0  right 1
            if (tNode.parent.leftChild == tNode) {
                stack.push("0");
            } else if (tNode.parent.rightChild == tNode) {
                stack.push("1");
            }
            tNode = tNode.parent;//往上走一步
        }
        System.out.println();
        while (!stack.isEmpty()) {
            System.out.print(stack.pop());
        }
    }

    /**
     * 结点
     *
     * @param <T>
     */
    public static class TreeNode<T> implements Comparable<TreeNode<T>> {
        T data;
        int weight;
        TreeNode leftChild;
        TreeNode rightChild;
        TreeNode parent;

        public TreeNode(T data, int weight) {
            this.data = data;
            this.weight = weight;
            leftChild = null;
            rightChild = null;
            parent = null;
        }

        @Override
        public int compareTo(@NonNull TreeNode<T> o) {
            if (this.weight > o.weight) {
                return -1;
            } else if (this.weight < o.weight) {
                return 1;
            }
            return 0;
        }
    }
}

2,平衡树
二叉排序树有大量连续数据的时候可以压缩为平衡二叉树。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

qczg_wxg

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值