算法设计与分析典例总结

算法设计与分析典例总结

  • 排序算法
public class BubbleSort {
    //交换keys[i]和keys[j]元素,i,j范围由调用者控制
    public static void swap(int[] keys, int i, int j){
        int temp=keys[j];
        keys[j]=keys[i];
        keys[i]=temp;
    }

    //冒泡排序(升序)
    //添加交换信号量,控制是否继续下一趟排序。如果一趟扫描没有数据交换,则排序完成,不必进行下一趟
    public static void bubbleSort(int[] keys){
        boolean exchange=true;      //是否有交换的信号量
        for (int i=0; i<keys.length-1; i++){
            //第一层循环控制最多n-1趟扫描
            exchange=false;
            //第二层循环控制一趟扫描的比较和交换
            for (int j=0; j<keys.length-1-i; j++){
                if (keys[j]>keys[j+1]){
                    swap(keys,j,j+1);
                    exchange=true;
                }
            }
        }
    }
}

public class InsertSort {
    //插入排序(升序)
    public static void insertSort(int[] keys){
        for (int i=1; i<keys.length; i++){
            int temp=keys[i];
            int flag=i;
            int j=i;
            while (j>0 && temp<keys[j-1]){
                    keys[j]=keys[j-1];
                    flag=j;
                    j--;
            }
            keys[j]=temp;
        }
    }

    public static void main(String[] args) {
        int[] testNum={32,26,87,72,22};
        insertSort(testNum);
        for (int i=0; i<testNum.length; i++){
            System.out.println(testNum[i]);
        }
    }
}
public class MergeSort {
    //归并方法(将两个排好序的小数组合并为一个大数组)
    public static void merge(int[] keys, int begin, int midNum, int end){
        int j,k,h;
        j=begin;
        h=midNum+1;
        k=begin;
        int a[]=new int[keys.length];
        while(j<=midNum && h<=end){
            if (keys[j]<keys[h]){
                a[k++]=keys[j++];
            }
            else{
                a[k++]=keys[h++];
            }
        }

        //将剩余数据加入到辅助数组中
        while(j<=midNum){
            a[k++]=keys[j++];
        }
        while(h<=end){
            a[k++]=keys[h++];
        }

        //将辅助数组的数据复制到原数组的对应位置上
        for (k=begin; k<=end; k++){
            keys[k]=a[k];
        }
    }

    //二分归并排序(升序)
    //begin和end指准备排序数组的开始和终止位置,起始值为0和keys.length-1
    public static void mergeSort(int[] keys, int begin, int end) {
        if (begin<end) {
            int midNum = (end+begin) / 2;
            //递归
            mergeSort(keys, begin, midNum);
            mergeSort(keys, midNum + 1, end);
            //归并
            merge(keys, begin, midNum, end);
        }
    }

    public static void main(String[] args) {
        int[] testNum={26,32,22,87};
        merge(testNum,0,1,3);
        for (int i=0; i<testNum.length; i++){
            System.out.println(testNum[i]);
        }

        System.out.println("*******************");

        int[] test={32,26,87,73,66,55,99,75,74};
        mergeSort(test,0,8);
        for (int i=0; i<test.length; i++){
            System.out.println(test[i]);
        }
    }
}
public class QuickSort {
    //划分数组方法
    //以数组的首元素作为划分依据,将该元素经过比较后放在指定位置
    //这个元素前面的元素全部小于它,这个元素后面的元素全部大于它
    public static int Partition(int[] keys, int begin, int end){
        int i=begin;
        int j=end;
        int accordingNum=keys[begin];

        while(i<j){
            while(keys[j]<=accordingNum && i<j){
                j--;
            }
            while(keys[i]>=accordingNum && i<j){
                i++;
            }
            if(i<j){
                swap(keys, i, j);
                i++;
                j--;
            }
        }
        return j;
    }
    //元素交换方法
    public static void swap(int[] keys, int x, int y){
        int temp=keys[x];
        keys[x]=keys[y];
        keys[y]=temp;
    }

    //快速排序(升序)
    //begin和end分别为将要排序数组的起始位置和终止位置,
    //begin起始值为0,end起始值为keys.length-1
    public static void quickSort(int[] keys, int begin, int end){
        if(begin<end){
            int flag=Partition(keys, begin, end);
            swap(keys, begin, flag);
            quickSort(keys, begin, flag-1);
            quickSort(keys, flag+1, end);
        }
    }

    public static void main(String[] args){
        int[] testList={27,7,98,3,96,95};
        quickSort(testList, 0, 5);
        for(int i=0; i<testList.length; i++){
            System.out.println(testList[i]);
        }
    }
}
public class SelectSort {
    //交换keys[i]和keys[j]元素,i,j范围由调用者控制
    public static void swap(int[] keys, int i, int j){
        int temp=keys[j];
        keys[j]=keys[i];
        keys[i]=temp;
    }

    //插入排序(升序)
    public static void selectSort(int[] keys){
        for (int i=0; i<keys.length-1; i++){
            int flag=i;
            for (int j=i+1; j<keys.length; j++){
                if (keys[j]<keys[i]){
                    flag=j;
                }
            }
            swap(keys,i,flag);
        }
    }

    public static void main(String[] args) {
        int[] testNum={32,26,87,72,17};
        selectSort(testNum);
        for (int i=0; i<testNum.length; i++){
            System.out.println(testNum[i]);
        }
    }
}
  • 分治算法
public class BinarySearch {
    //二分查找算法(迭代)
    //输入排好序的数组keys和要查找的数x
    //返回x在数组中的下标,若没有找到,返回0
    public static int binarySearch(int[] keys, int x){
        int i=0;
        int j=keys.length-1;
        int flag;
        while(i<=j){
            flag=(i+j)/2;
            if (keys[flag]==x){
                return flag;
            }
            else if (keys[flag]>x){
                j=flag-1;
            }
            else{
                i=flag+1;
            }
        }
        return 0;
    }

    //二分查找(递归实现)
    public static int binarySearch2(int[] keys, int x){
        return binarySearch3(keys,x,0,keys.length-1);
    }

    public static int binarySearch3(int[] keys, int x, int begin, int end){
        int i=begin;
        int j=end;
        int flag=(begin+end)/2;
        if (i<=j){
            if (x==keys[flag]){
                return flag;
            }
            else if (x>keys[flag]){
                return binarySearch3(keys,x,flag+1,end);
            }
            else{
                return binarySearch3(keys,x,begin,flag-1);
            }
        }
        return 0;
    }

    public static void main(String[] args) {
        int[] testList={1,2,3,4,5};
        int result;
        result=binarySearch2(testList,-1);
        System.out.println(result);
    }
}
public class FindSecond {
    //找到数组中第二大的元素(锦标赛算法)
    //以空间换时间
    public static void findSecond(int[] keys){
        int length=keys.length;
        int compareListLength=length*2;
        int[] compareList=new int[compareListLength];
        int max;
        int second=-1;

        for (int i=length; i<compareListLength; i++){
            compareList[i]=keys[i-length];
        }

        for (int i=compareListLength-2; i>=2; i=i-2){
            compareList[i/2]=Math.max(compareList[i],compareList[i+1]);
        }

        max=compareList[1];

        for (int i=1; 2*i<compareListLength; ){
            if (compareList[2*i]==compareList[i]){
                if (second<compareList[2*i+1]){
                    second=compareList[2*i+1];
                }
                i=2*i;
            }
            else {
                if (second<compareList[2*i]){
                    second=compareList[2*i];
                }
                i=2*i+1;
            }
        }

        System.out.println("max:" + max);
        System.out.println("second:" + second);
    }

    public static void main(String[] args) {
        int[] testList={5,3,1,2,4};
        findSecond(testList);
    }
}
  • 动态规划算法
//最优二叉检索树算法(动态规划求解)
public class BestBinarySearchTree {
    //求解最优二叉检索树方法
    //方法参数: 检索序列s, 概率分布数组p, 动态规划数组m, 标记数组k
    public static double bestBinarySearchTree(int[] s, double[] p, double[][] m, int[][] k){
        int s_length=s.length-1;
        int p_length=p.length-1;

        //初始化动态数组,令m[i][i-1]=0,m[i][i]等于其各自的概率
        //初始化标记函数
        for (int i=1; i<=s_length; i++){
            m[i][i-1]=0;
            k[i][i-1]=0;
        }
        for (int i=1; i<=s_length; i++){
            m[i][i]=p[2*i-1]+p[2*i]+p[2*i+1];
            k[i][i]=i;
        }

        int l=0;
        double min=0;

        //递归求解动态规划数组
        //子问题规模从2开始
        for (int i=2; i<=s_length; i++){
            //子问题规模为i时可能存在的划分情况
            for (int j=1; j<=s_length-i+1; j++){
                l=j+i-1;

                //求解将两子问题合并的概率
                double w=calculateW(j,l,p);

                m[j][l]=m[j][j-1]+m[j+1][l]+w;
                k[j][l]=0;

                for (int o=j+1; o<=l-1; o++){
                    double result=m[j][o-1]+m[o+1][l]+w;
                    if (result<m[j][l]){
                        min=result;
                        m[j][l]=result;
                        k[j][l]=o;
                    }
                }
            }
        }
        return min;
    }

    //求解w方法
    //参数描述: begin和end分别为起始和终止位置, p为概率分布数组
    public static double calculateW(int begin, int end, double[] p){
        double w;
        w=p[2*begin-1]+p[2*begin]+p[2*begin+1];
        for (int i=begin+1; i<=end; i++){
            w += p[2*i]+p[2*i+1];
        }
        return w;
    }

    public static void main(String[] args) {
        int[] s={0,1,2,3,4,5};
        double[] p={0,0.04,0.1,0.02,0.3,0.02,0.1,0.05,0.2,0.06,0.1,0.01};

        double[][] m=new double[s.length][s.length];
        int[][] k=new int[s.length][s.length];

        double result=bestBinarySearchTree(s,p,m,k);
        System.out.println(result);

        for (int i=1; i<s.length; i++){
            for (int j=1; j<s.length; j++){
                System.out.print(m[i][j]+ " ");
            }
            System.out.println();
        }

        System.out.println("******************************");

        for (int i=1; i<k.length; i++){
            for (int j=1; j<k.length; j++){
                System.out.print(k[i][j]+ " ");
            }
            System.out.println();
        }
    }
}
public class KnapsackProblem {
    /**
     * 完全背包问题
     * 问题描述:可以放入背包的物品有n种,物品j的重量和价值分别为wj和vj,背包最大重量限制为b
     * 怎样选择使放入背包的物品的价值最大
     */

    //求解完全背包问题方法
    //方法参数: 物品种类个数n, 背包总重量限制b, 每个种类物品对应的重量weight, 每个物品对应的价值value, 动态规划数组dp, 标记数组flag
    //二维数组的第一个参数代表物品种类限制(1-n),第二个参数代表背包重量限制(1-b)
    public static void completePack(int n, int b, int[] weight, int[] value, int[][] dp, int[][] flag){
        //令所有dp[i][0]和dp[0][i]均为0
        for (int i=1; i<=n; i++){
            dp[i][0]=0;
        }
        for (int i=1; i<=b; i++){
            dp[0][i]=0;
        }

        //令所有flag[i][0]和flag[0][i]均为0
        for (int i=1; i<=n; i++){
            flag[i][0]=0;
        }
        for (int i=1; i<=b; i++){
            flag[0][i]=0;
        }

        //物品种类递增,对子问题求解(物品种类的限制)
        for (int k=1; k<=n; k++){
            //背包总重量递增,对子问题求解(物品重量的限制)
            for (int y=1; y<=b; y++){
                //如果物品重量大于背包的重量限制,不装入
                if (weight[k]>y){
                    dp[k][y]=dp[k-1][y];
                    flag[k][y]=flag[k-1][y];
                }
                else {
                    if (dp[k-1][y]>dp[k][y-weight[k]]+value[k]){
                        flag[k][y]=flag[k-1][y];
                    }
                    else{
                        flag[k][y]=k;
                    }
                    dp[k][y]=Math.max(dp[k-1][y], dp[k][y-weight[k]]+value[k]);
                }
            }
        }
    }
    //追踪解过程的方法
    //参数: 标记数组flag, 追踪后得到的解数组solution, 物品的种类个数n, 背包的总重量限制b, 每个种类物品的重量数组weight
    public static void trackSolution(int b, int n, int[][] flag, int[] solution, int[] weight){
        //首先将解数组赋初值为0
        for (int i=1; i<=n; i++){
            solution[i]=0;
        }
        int y=b;
        int j=n;
        do {
            j=flag[j][y];
            solution[j]=1;
            y=y-weight[j];
            while(flag[j][y]==j){
                y=y-weight[j];
                solution[j]=solution[j]+1;
            }
        }while(flag[j][y]!=0);
    }

    public static void main(String[] args) {
        int[] value={0,1,3,5,9};
        int[] weight={0,2,3,4,7};
        int b=10;

        int value_length=value.length;
        int weight_length=b;
        //初始化动态数组
        int[][] dp=new int[value_length][weight_length+1];

        //初始化flag数组
        int[][] flag=new int[value_length][weight_length+1];
        completePack(value_length-1, b, weight, value, dp, flag);
        System.out.println(dp[value_length-1][weight_length]);

        for (int i=1; i<value_length; i++){
            for (int j=1; j<=b; j++){
                System.out.print(flag[i][j] + " ");
            }
            System.out.println();
        }

        int[] solution=new int[value_length];
        trackSolution(b,value_length-1, flag, solution, weight);
        for (int i=1; i<value_length; i++){
            System.out.println(solution[i]);
        }
    }
}
//最长公共子序列问题
public class LCS {
    //最长公共子序列求解算法(动态规划求解)
    //方法参数: 序列x和序列y, 动态规划数组c, 标记数组flag
    //二维动态规划数组c的第一个参数代表序列x, 第二个参数代表序列y, flag数组同理
    //flag数组可赋值为0, 1, 2(0代表向斜上方回溯, 1代表向左边回溯, 2代表向上边回溯)
    public static void lcs(int[] x, int[] y, int[][] c, int[][] flag){
        int x_length=x.length;
        int y_length=y.length;

        //令动态规划数组中的c[0][i]和c[i][0]均为0
        for (int i=1; i<x_length; i++){
            c[i][0]=0;
        }
        for (int i=1; i<y_length; i++){
            c[0][i]=0;
        }

        //递归求解动态规划数组和标记数组
        for (int i=1; i<x_length; i++){
            for (int j=1; j<y_length; j++){
                if (x[i]==y[j]){
                    c[i][j]=c[i-1][j-1]+1;
                    flag[i][j]=0;
                }
                else {
                    if (c[i-1][j]>=c[i][j-1]){
                        c[i][j]=c[i-1][j];
                        flag[i][j]=2;
                    }
                    else {
                        c[i][j]=c[i][j-1];
                        flag[i][j]=1;
                    }
                }
            }
        }
    }

    //追踪解的方法
    //方法参数: 标记数组flag, 序列x的长度i, 序列y的长度j, 序列x, 保存结果的数组result
    public static void structureSequence(int[][] flag, int i, int j, int[] x, int[] result){
        //一个序列为空
        if (i==0 || j==0)
            return;

        if (flag[i][j]==0){
            result[i]=x[i];
            structureSequence(flag,i-1,j-1,x,result);
        }
        else if (flag[i][j]==1){
            structureSequence(flag,i,j-1,x,result);
        }
        else {
            structureSequence(flag,i-1,j,x,result);
        }
    }

    public static void main(String[] args) {
        //序列x
        int[] x={0,1,2,3,2,4,1,2};
        //序列y
        int[] y={0,2,4,3,1,2,1};

        int x_length=x.length;
        int y_length=y.length;

        //初始化动态规划数组
        int[][] c=new int[x_length][y_length];
        //初始化标记数组
        int[][] flag=new int[x_length][y_length];

        lcs(x,y,c,flag);
        System.out.println(c[x_length-1][y_length-1]);

        int[] result=new int[x_length];
        structureSequence(flag,x_length-1,y_length-1,x,result);

        for (int i=0; i<x_length; i++){
            System.out.println(result[i]);
        }
    }
}
public class MatrixChain {
    //矩阵链乘法(迭代算法)
    //输入为矩阵链数组keys, 优化函数值的备忘录m, 标记函数备忘录s
    //输出计算一系列矩阵的最小乘法次数m[i][j]和最后一次运算的位置s[i][j]
    public static int matrixChain(int[] keys, int[][] m, int[][] s){
        int keys_length=keys.length-1;
        //令所有的m[i][i]初值为0,s[i][j]初值为i(子问题规模为1时)
        for (int i=1; i<keys_length; i++){
            m[i][i]=0;
        }
        for (int i=1; i<keys_length-1; i++){
            s[i][i+1]=i;
        }

        int k=0;
        int min=0;

        //子问题规模从2到keys_length
        for(int i=2; i<=keys_length; i++){
            //子问题规模为i时可能出现的情况
            for (int j=1; j<keys_length-i+1; j++){
                k=j+i-1;
                m[j][k]=m[j+1][k]+keys[j]*keys[j+1]*keys[k+1];  //划分为Aj(Aj+1...Ak)作为比较的初值
                s[j][k]=j;  //记录初始的分割位置
                //计算子问题规模为i时最小次数的乘法
                //t为划分的位置
                for (int t=j+1; t<=k-1; t++){
                    int result=m[j][t]+m[t+1][k]+keys[j]*keys[t+1]*keys[k+1];
                    if (result<m[j][k]){
                        min=result;
                        m[j][k]=result;
                        s[j][k]=t;
                    }
                }
            }
        }
        return min;
    }

    public static void main(String[] args) {
        int[] keys={0,30,35,15,5,10,20};
        int length=keys.length-1;
        int[][] m=new int[length][length];
        int[][] s=new int[length][length];

        int min=matrixChain(keys,m,s);
        System.out.println(min);

        for (int i=1; i<6; i++){
            for (int j=1; j<6; j++){
                System.out.print(m[i][j] + " ");
            }
            System.out.println();
        }
    }
}

public class MaxSum {
    //求解最大子段和(分治算法)
    //方法参数: 求解序列a, 序列a的左边界left, 序列a的右边界right
    public static int maxSubSum(int[] a, int left, int right){
        //递归终止条件
        if (left==right){
            return a[left];
        }

        int center=(left+right)/2;
        int leftSum;
        int rightSum;

        //递归,分别求解序列a左半部分,右半部分和中间跨边界部分,然后经过比较求得最大值
        leftSum=maxSubSum(a, left, center);
        rightSum=maxSubSum(a, center+1,right);

        int s1=0;
        int s2=0;
        int lefts=0;
        int rights=0;

        //从center向左得最大和
        for (int i=center; i>=left; i--){
            lefts += a[i];
            if (lefts>s1){
                s1=lefts;
            }
        }
        //从center+1向右的最大和
        for (int i=center+1; i<=right; i++){
            rights += a[i];
            if (rights>s2){
                s2=rights;
            }
        }

        int sum=s1+s2;

        if (leftSum>sum){
            sum=leftSum;
        }
        if (rightSum>sum){
            sum=rightSum;
        }

        return sum;
    }

    //求解最大子段和(动态规划算法)
    //参数描述: 求解序列a, 动态规划数组c, 序列中元素的个数n
    public static int maxSum(int[] a, int[] c, int n){
        int a_length=n;
        //初始化动态数组
        c[0]=a[0];

        //动态规划计算
        for (int i=1; i<a_length; i++){
            if (c[i-1]+a[i]>=a[i]){
                c[i]=c[i-1]+a[i];
            }
            else {
                c[i]=a[i];
            }
        }

        int max=0;
        int c_length=c.length;
        for (int i=0; i<c_length; i++){
            if (c[i]>max){
                max=c[i];
            }
        }
        return max;
    }

    public static void main(String[] args) {
        int[] test={-2,11,-4,13,-5,-2};
        int result=maxSubSum(test,0,5);
        System.out.println(result);

        int[] c=new int[test.length];
        int result2=maxSum(test,c,test.length);
        System.out.println(result2);
    }
}
  • 贪心算法
public class Dijkstra {

    private static final int MAX=100001;

    //迪杰斯克拉算法(求解从带权有向图源点出发到达每个其它结点的最短路径)
    //参数描述: w代表有向带权图矩阵, start代表起点编号
    //返回一个int[]数组, 表示从start到它的最短路径长度
    public static int[] dijkstra1(int[][] w, int start){
        int length=w.length;
        int[] shortPath=new int[length];    //存放从start到各个点的最短的距离
        String path[]=new String[length];   //存放从start点到各点的最短路径的字符串表示
        for (int i=0; i<length; i++){
            path[i]=start+ "->" + i;
        }
        int visited[]=new int[length];      //标记当前该顶点的最短路径是否已经求出, 1表示已经求出
        visited[0]=1;       //start点的最短距离已经求出
        for (int count=1; count<length; count++){
            int k=-1;
            int d_min=Integer.MAX_VALUE;
            for (int i=0; i<length; i++){
                if (visited[i]==0 && w[start][i]<d_min){
                    d_min=w[start][i];
                    k=i;
                }
            }
            //选出一个距离start最近的未标记的顶点, 将新选出的顶点标记为以求出最短路径,且到start的最短路径为d_min
            shortPath[k]=d_min;
            visited[k]=1;
            //以k为中间点,修正从start到未访问各点的距离
            for (int i=0; i<length; i++){
                if (visited[i]==0 && w[start][k]+w[k][i]<w[start][i]){
                    w[start][i]=w[start][k]+w[k][i];
                    path[i]=path[k] + "->" + i;
                }
            }
        }
        for (int i=0; i<length; i++){
            System.out.println("从" + start + "出发到" + i + "的最短路径为:" + path[i] + "=" + shortPath[i]);
        }
        return shortPath;
    }

    //迪杰斯特拉算法
    public static void dijkstra2(int[][] w, int start){
        int length=w.length;

        int[] visited=new int[length];      //用visited数组代表将图划分为S和V-S集合,放入S集合用1表示,在V-S集合中用0表示
        int[] dist=new int[length];         //用dist数组表示从start点出发中间只经过S集合中元素且最终到达i的最短路径
        String[] path=new String[length];   //path[j]数组用来记录start到j的最短路径上j前一个结点的标号

        visited[0]=1;
        //初始化dist数组
        dist[0]=0;
        for (int i=1; i<length; i++){
            dist[i]=w[start][i];
        }

        //初始化path数组
        for (int i=0; i<length; i++){
            path[i]=start+ "->" + i;
        }

        //循环length次,依次将V-S集合中的元素加入S集合中去
        for (int i=1; i<length; i++){
            int k=-1;
            int d_min=Integer.MAX_VALUE;
            for (int j=0; j<length; j++){
                if (visited[j]==0 && dist[j]<d_min){
                    d_min=dist[j];
                    k=j;
                }
            }

            visited[k]=1;

            for (int j=0; j<length; j++){
                if (visited[j]==0 && dist[k]+w[k][j]<dist[j]){
                    dist[j]=dist[k]+w[k][j];
                    path[j]=path[k] + "->" + j;
                }
            }
        }
        for (int i=0; i<length; i++){
            System.out.println("从" + start + "出发到" + i + "的最短路径为:" + path[i] + "=" + dist[i]);
        }
    }

    public static void main(String[] args) {
        int[][] weight = {
                {0,10,MAX,MAX,MAX,3},
                {MAX,0,7,5,MAX,MAX},
                {MAX,MAX,0,MAX,MAX,MAX},
                {3,MAX,4,0,7,MAX},
                {MAX,MAX,MAX,MAX,0,MAX},
                {MAX,2,MAX,6,1,0},
        };
        int start = 0;
        dijkstra2(weight,start);
        System.out.println("*****************");
        dijkstra1(weight,start);
    }
}
//哈夫曼树结点类
class HufTreeNode implements Comparable<HufTreeNode>{
    private char value; //结点值
    private int data;   //权值
    private HufTreeNode left;   //左子树
    private HufTreeNode right;  //右子树

    public HufTreeNode(char value, int data, HufTreeNode left, HufTreeNode right){
        this.value=value;
        this.data=data;
        this.left=left;
        this.right=right;
    }

    public char getValue() {
        return value;
    }

    public void setValue(char value) {
        this.value = value;
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public HufTreeNode getLeft() {
        return left;
    }

    public void setLeft(HufTreeNode left) {
        this.left = left;
    }

    public HufTreeNode getRight() {
        return right;
    }

    public void setRight(HufTreeNode right) {
        this.right = right;
    }

    @Override
    public int compareTo(HufTreeNode o) {
        return this.getData()-o.getData();
    }
}

public class Huffman {
    //哈夫曼算法生成最优二元前缀码
    //参数描述:map是字符和权值的键值对
    public static void huffman(HashMap<Character, Integer> map){
        //创建优先队列存储结点
        PriorityQueue<HufTreeNode> queue=new PriorityQueue<>();
        for (Map.Entry<Character, Integer> entry : map.entrySet()){
            HufTreeNode node=new HufTreeNode(entry.getKey(), entry.getValue(), null, null);
            queue.add(node);
        }

        //队列中还剩下一个结点时循环结束
        while(queue.size()>1){
            //队列中最小的两个元素出队
            HufTreeNode x=queue.poll();
            HufTreeNode y=queue.poll();

            HufTreeNode z=new HufTreeNode('z', x.getData()+y.getData(), x, y);
            queue.add(z);
        }

        //返回哈夫曼树的根结点(即是队列中剩余的最后一个元素)
        HufTreeNode root=queue.poll();

        String huffCode="";

        printHuffCode(root,huffCode);
    }

    //根据哈夫曼树生成最优二元前缀码(递归实现)
    public static void printHuffCode(HufTreeNode root, String huffCode){
        if (root.getLeft()==null || root.getRight()==null){
            System.out.println("值为" + root.getValue() + ",权值为" + root.getData() + "的二元前缀码为" + huffCode);
        }
        if (root.getLeft()!=null){
            printHuffCode(root.getLeft(), huffCode+'0');
        }
        if (root.getRight()!=null){
            printHuffCode(root.getRight(), huffCode+'1');
        }
    }

    public static void main(String[] args) {
        HashMap<Character, Integer> map=new HashMap<>();

        map.put('a',9);
        map.put('b',12);
        map.put('c',6);
        map.put('d',3);
        map.put('e',5);
        map.put('f',15);

        huffman(map);
    }
}
public class MinSpanTree {
    //最小生成树算法(Prim)
    //参数描述: w是图中相邻两点边的长度(无向带权图), near[i]是集合S中距离i最近的顶点, 数组e代表结点数组, n是顶点的个数
    //Prim算法基本思想是将V划分成两个子集S与V-S,算法每一步从联通S与V-S的边中挑选一条权最小的边,
    //然后把这条边所关联的顶点加到S中去

    private static final int MAX=1000001;

    public static void prim(int[][] w, int[] near, int n){
        //创建S和V-S集合
        int[] s=new int[n];
        int[] s_v=new int[n];

        //d[i]是这个最近的结点到i的距离
        int[] d=new int[n+1];

        //初始状态,将第一个元素放入S集合,将其他元素放入V-S集合
        s[0]=1;
        for (int i=0; i<n-1; i++){
            s_v[i]=i+2;
        }

        //初始化near数组
        for (int i=2; i<=n; i++){
            near[i]=1;
        }

        //初始化d数组
        for (int i=2; i<=n; i++){
            d[i]=w[1][i];
        }

        //循环比较V-S集合中的所有元素,即从第2个元素到第n个元素
        for (int i=0; i<n-1; i++){
            int min=MAX;
            int result=2;
            for (int j=2; j<=n; j++){
                if (d[j]<min && d[j]>0){
                    min=d[j];
                    result=j;
                }
            }
            s[i+1]=result;
            d[result]=-1;

            for (int k=2; k<=n; k++){
                if (w[k][result]<d[k]){
                    d[k]=w[k][result];
                    near[k]=result;
                }
            }
        }

        for (int i=2; i<=n; i++){
            System.out.println(i + " ----> " + near[i]);
        }
    }


    public static void main(String[] args) {
        //初始化无向带权图
        int[][] w=new int[7][7];
        w[1][2]=w[2][1]=6;
        w[1][3]=w[3][1]=1;
        w[1][4]=w[4][1]=5;
        w[1][5]=w[5][1]=MAX;
        w[1][6]=w[6][1]=MAX;
        w[2][3]=w[3][2]=5;
        w[2][4]=w[4][2]=MAX;
        w[2][5]=w[5][2]=3;
        w[2][6]=w[6][2]=MAX;
        w[3][4]=w[4][3]=5;
        w[3][5]=w[5][3]=6;
        w[3][6]=w[6][3]=4;
        w[4][5]=w[5][4]=MAX;
        w[4][6]=w[6][4]=2;
        w[5][6]=w[6][5]=6;

        //初始化near数组
        int[] near=new int[7];

        prim(w, near, 6);
    }
}

  • 回溯算法
//四皇后问题(回溯算法求解)
public class FourQueens {

    //皇后的放置方案
    static int count=0;

    //判断该位置是否可存放皇后
    private boolean isVaild(char[][] queen, int row, int col){
        //先判断上面是否已经放置有Q
        for (int i=row-1; i>=0; i--){
            //此位置的上面,列不变向上找行
            if (queen[i][col]=='Q'){
                return false;   //一旦发现,此位置不能放
            }
        }
        //判断右上位置是否存有Q
        for (int i=row-1, j=col+1; i>=0 && j<queen[0].length; i--, j++){
            if (queen[i][j]=='Q'){
                return false;
            }
        }
        //判断左上位置是否有Q
        for (int i=row-1, j=col-1; i>=0 && j>=0; i--, j--){
            if (queen[i][j]=='Q'){
                return false;
            }
        }
        //如果都没找到,则此位置可以存放
        return true;
    }

    //打印数组
    private void printQueen(char[][] queen){
        for (int i=0; i<queen.length; i++){
            for (int j=0; j<queen.length; j++){
                System.out.print(queen[i][j]);
            }
            System.out.println();
        }
    }

    //初始化数组
    private void initializeQueen(char[][] queen){
        for (int i=0; i<queen.length; i++){
            for (int j=0; j<queen.length; j++){
                queen[i][j]='A';
            }
        }
    }

    //回溯法求二维数组中皇后存放方法
    public void queen(char[][] queen, int row){
        //结束条件: 即当row为数组的长度时结束
        if (row==queen.length){
            count++;
            printQueen(queen);

            System.out.println();

            return;
        }

        for (int col=0; col<queen.length; col++){
            if (isVaild(queen, row, col)){
                //如果在当前位置放一个皇后不冲突,就在当前位置放置皇后
                queen[row][col]='Q';
                //递归执行下一行
                queen(queen, row+1);
                //撤销当前位置的皇后(回溯)
                queen[row][col]='A';
            }
        }
    }

    public static void main(String[] args) {
        char[][] chars=new char[4][4];
        FourQueens queens=new FourQueens();
        queens.initializeQueen(chars);
        queens.queen(chars, 0);
        System.out.println("总共有" + count + "种放置方法");
    }
}
//装载问题(回溯算法)(未采用剪枝操作,时间复杂度较高)
public class Loading {
    //用回溯算法求解装载问题
    //参数描述: 集装箱重量序列w, 第一条船的载重c1
    public static int[] loading(int[] w, int c1) {
        int b = c1;       //b为目前空隙
        int best = c1;    //best为目前为止最优解空隙

        int i=0;
        int n = w.length; //集装箱的数量
        int[] x=new int[n];   //x记录集装箱的装入情况,1代表已经装入,0代表未装入,初始时均为0,即代表均未装入
//        QuickSort.quickSort(w, 0, n - 1);   //将集装箱质量按照从大到小排序
        int[] x_flag=new int[n];

        while (true) {
            while (i < n) {
                b -= w[i];
                if (b>=0) {
                    x[i] = 1;
                }
                else {
                    x[i] = 0;
                    b += w[i];
                }
                i++;
            }

            i--;

            if (b < best) {
                best = b;
                for (int count=0; count<n; count++){
                    x_flag[count]=x[count];
                }
            }

            int[] flag=backTrack(i,x,b,w);
            i=flag[0];
            b=flag[1];

            if (i==0){
                return x_flag;
            }
            else {
                continue;
            }
        }
    }

    //回溯
    public static int[] backTrack(int i, int[] x, int b, int[] w){
        int[] flag=new int[2];

        while(i>0 && x[i]==0){
            i=i-1;
        }
        if (x[i]==1){
            x[i]=0;
            b += w[i];
            i=i+1;
        }

        flag[0]=i;
        flag[1]=b;

        return flag;
    }

    public static void main(String[] args) {
        int[] w={90,80,40,30,20,12,10};
        int c1=152;
        int[] x_flag=loading(w,c1);
        for (int i=0; i<7; i++){
            System.out.print(x_flag[i] + " ");
        }
    }
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值