Java拓扑排序

330 阅读4分钟

Java拓扑排序

/**
 * 边表结点
 */
class EdgeNode {
    int data;
    int weight;
    EdgeNode next;
    public EdgeNode(int data, int weight, EdgeNode next) {
        this.data = data;
        this.weight = weight;
        this.next = next;
    }
    public EdgeNode(int data, EdgeNode next) {
        this.data = data;
        this.next = next;
    }
}
/**
 * 顶点表结点
 */
class VertexNode {
    int in;//入度
    int data;
    EdgeNode first;
    public VertexNode(int in, int data, EdgeNode first) {
        this.in = in;
        this.data = data;
        this.first = first;
    }
}
public class AOV网与拓扑排序 {
    VertexNode[] graphAdjList = new VertexNode[9];
    //etv(Earliest Time Of Vertex) 事件最早发生时间,顶点最早发生时间
    int[] etv = new int[9];
    //ltv(Latest Time Of Vertex)   事件最晚发生时间,顶点最晚发生时间
    int[] ltv = new int[9];
    //ete(Earliest Time Of Edge)  活动最早开始时间,边最早开始时间
    int[] ete = new int[9];
    //lte(Latest Time Of Edge)     活动最晚开始时间,边最晚开始时间
    int[] lte = new int[9];

    int[] stack2 = new int[9];
    int top2 = 0;

    @Test
    public void test() {
        EdgeNode a = new EdgeNode(3, 5, null);
        EdgeNode a2 = new EdgeNode(2, 4, a);
        EdgeNode a3 = new EdgeNode(1, 6, a2);
        graphAdjList[0] = new VertexNode(0, 1, a3);

        EdgeNode b1 = new EdgeNode(4, 1, null);
        graphAdjList[1] = new VertexNode(1, 2, b1);

        EdgeNode c1 = new EdgeNode(4, 1, null);
        graphAdjList[2] = new VertexNode(1, 3, c1);

        EdgeNode d1 = new EdgeNode(5, 2, null);
        graphAdjList[3] = new VertexNode(1, 4, d1);

        EdgeNode e1 = new EdgeNode(7, 5, null);
        EdgeNode e2 = new EdgeNode(6, 7, e1);
        graphAdjList[4] = new VertexNode(2, 5, e2);

        EdgeNode f2 = new EdgeNode(7, 4, null);
        graphAdjList[5] = new VertexNode(1, 6, f2);

        EdgeNode f3 = new EdgeNode(8, 2, null);
        graphAdjList[6] = new VertexNode(1, 7, f3);

        EdgeNode f4 = new EdgeNode(8, 4, null);
        graphAdjList[7] = new VertexNode(2, 8, f4);

        graphAdjList[8] = new VertexNode(2, 9, null);
        criticalPath();
    }

    /**
     * 拓扑排序
     */
    public void topologicalSort() {
        int top = 0;//栈顶指针
        int[] stack = new int[9];//用来存放入度为0的顶点
        //循环得到入度为0的所有顶点
        for (int i = 0; i < graphAdjList.length; i++) {
            if (graphAdjList[i].in == 0) {
                stack[++top] = i;
            }
        }
        //开始算法的逻辑
        while (top != 0) {
            int getTop = stack[top--];//出栈一个
//            System.out.print("  "+graphAdjList[getTop].data);
            //保存拓扑序列顺序
            stack2[top2++] = getTop;

            //更新当前输出节点所有的出边(后继顶点)
            for (EdgeNode e = graphAdjList[getTop].first; e != null; e = e.next) {
                int k = e.data;
                //入度减一
                graphAdjList[k].in--;
                if (graphAdjList[k].in == 0) {
                    stack[++top] = k;
                }
                //计算顶点的最早开始时间
                if ((etv[getTop] + e.weight) > etv[k]) {
                    etv[k] = etv[getTop] + e.weight;
                }

            }

        }


    }
    public void criticalPath() {
        topologicalSort();
        //初始化ltv都为汇点时间
        for(int i=0;i<9;i++) {
            ltv[i]=etv[8];
        }
        //从汇点开始倒过来计算ltv
        while(top2>0) {
            int getTop=stack2[--top2];//从汇点开始
            for (EdgeNode e = graphAdjList[getTop].first; e != null; e = e.next) {
                int k=e.data;
                if(ltv[k]-e.weight<ltv[getTop]) {
                    ltv[getTop]=ltv[k]-e.weight;
                }
            }
        }
        //通过etv和ltv计算出ete和lte
        for (int i = 0; i < 9; i++) {
            for (EdgeNode e = graphAdjList[i].first; e != null; e = e.next) {
                int k=e.data;
                ete[i]=etv[i];//边的最早时间,就是顶点的最早时间
                lte[i]=ltv[k]-e.weight;//ltv[k]里面已经是选的最小的权重
                if(ete[i]==lte[i]){
                    System.out.println(graphAdjList[i].data+" "+graphAdjList[k].data+" "+e.weight);
                }

            }
        }

    }
}

SHA算法

public class SHA算法 {
    //1.准备工作
    public static final int[] abcde = {
            0x67452301,
            0xEFCDAB89,
            0x98BADCFE,
            0x10325476,
            0xC3D2E1F0
    };
    //摘要数据存储用的数组(存放密文的)  20个字节*8=160;
    public static int[] h=new int[5];
    //计算过程中需要用到的临时数据存储数组
    public static int[] m=new int[80];

    //定义辅助方法

    //将字符转换为十六进制字符串
    public static String byteToHexString(byte b){//97
        char[] digit={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
        char[] ob=new char[2];
        ob[0]=digit[(b>>>4)&0x0F];//9
        ob[1]=digit[b&0x0f];//7
        String s=new String(ob);//"97"
        return s;
    }
    //将字节数组转换为十六进制字符串
    public static String byteArrayToHexString(byte[] byteArray){
        String strDigest="";
        for(int i=0;i<byteArray.length;i++){
            strDigest+=byteToHexString(byteArray[i]);
        }
        return strDigest;
    }

    //4字节数组转换为int  i个byte合成到byteData[]中
    public static int byteArrayToInt(byte[] byteData,int i){
        //0a 0b 0c 0d  24       16       8       0
        //         0a000000  or  0b0000  or   0c00  or   0d
        //            0a0b0c0d
        return ((byteData[i]&0xff)<<24)|((byteData[i+1]&0xff)<<16)|((byteData[i+2]&0xff)<<8)|(byteData[i+3]&0xff);
    }
    //整数转换为4字节数组   int分解到byte数组中
    public static void intToByteArray(int intValue,byte[] byteData,int i){
        byteData[i]=(byte)((intValue>>>24)&0xff);
        byteData[i+1]=(byte)((intValue>>>16)&0xff);
        byteData[i+2]=(byte)((intValue>>>8)&0xff);
        byteData[i+3]=(byte)((intValue&0xff));
    }
    /*
    Ft(b,c,d)  ((b&c)|((~b)&d))    (0 <= t <= 19)
    Ft(b,c,d) (b^c^d)             (20 <= t <= 39)
    Ft(b,c,d) ((b&c)|(b&d)|(c&d))  (40 <= t <= 59)
    Ft(b,c,d) (b^c^d)               (60 <= t <= 79)
     */
    public static int f1(int x,int y,int z){
        return (x&y)|(~x&z);
    }
    public static int f2(int x,int y,int z){
        return x^y^z;
    }
    public static int f3(int x,int y,int z){
        return (x&y)|(x&z)|(y&z);
    }
    public static int f4(int x,int y,int z){
        return x^y^z;
    }

    //开始逻辑
    //进行对原数据的补位
    public static byte[] byteArrayFormatData(byte[] byteData){
        //补0的个数
        int fill=0;
        //补位后的总位数,64的倍数
        int size=0;
        //原数据的长度
        int srcLength=byteData.length;
        //对64求余数   n%512      56数据    8长度   53
        int m=srcLength%64;
        if(m<56){
            fill=55-m;
            size=srcLength-m+64;//数据只有一块
        }else if(m==56){
            fill=63;
            size=srcLength+8+64;
        }else{
            fill=63-m+56;//   58    60+56  116-64=52   55-52=3
            size=(srcLength+64)-m+64;
        }
        //补位后生成的新数组的内容
        byte[] newbyte=new byte[size];
        System.arraycopy(byteData,0,newbyte,0,srcLength);

        //补1
        int startLocation=srcLength;
        newbyte[startLocation++]=(byte)0x80;
        //补0
        for(int i=0;i<fill;i++){
            newbyte[startLocation++]=(byte)0x00;
        }
        //处理长度的位置  字节*8=?位   512-468=64位,用来存放长度
        long n=(long)srcLength*8;
        byte h8=(byte)(n&0xff);
        byte h7=(byte)((n>>8)&0xff);
        byte h6=(byte)((n>>16)&0xff);
        byte h5=(byte)((n>>24)&0xff);
        byte h4=(byte)((n>>32)&0xff);
        byte h3=(byte)((n>>40)&0xff);
        byte h2=(byte)((n>>48)&0xff);
        byte h1=(byte)((n>>56));
        newbyte[startLocation++]=h1;
        newbyte[startLocation++]=h2;
        newbyte[startLocation++]=h3;
        newbyte[startLocation++]=h4;
        newbyte[startLocation++]=h5;
        newbyte[startLocation++]=h6;
        newbyte[startLocation++]=h7;
        newbyte[startLocation++]=h8;

        return newbyte;
    }
    //开始计算密文 算摘要
    public static int process_input_bytes(byte[] byteData){
        System.arraycopy(abcde,0,h,0,abcde.length);
        //格式化数据
        byte[] newbyte=byteArrayFormatData(byteData);
        //计算有多少个大块
        int mCount=newbyte.length/64;
        //循环计算每一块的内容
        for(int pos=0;pos<mCount;pos++){
            //对每一块都进行加密计算
            //(1). 将 Mi 分成 16 个字 W0, W1, ... , W15,  W0 是最左边的字
            for(int i=0;i<16;i++){
                m[i]=byteArrayToInt(newbyte,(pos*64)+(i*4));
            }
            //计算
            encrypt();
        }

        return 20;
    }
    //n是一个整数且0<=n<=32。Sn(X) = (X<<n)OR(X>>(32-n))
    public static int s(int x,int i){
        return (x<<i)|x>>>(32-i);
    }
    public static void encrypt(){
        //(2). 对于 t = 1679 令
        // Wt = S1(Wt-3 XOR Wt-8 XOR Wt- 14 XOR Wt-16).
        for(int t=16;t<=79;t++){
            m[t]=s(m[t-3]^m[t-8]^m[t-14]^m[t-16],1);
        }
        //3.令 A = H0, B = H1, C = H2, D = H3, E = H4.
        int[] tempabcde=new int[5];
        for(int i=0;i<tempabcde.length;i++){
            tempabcde[i]=h[i];
        }
        //4.对于 t = 079,执行下面的循环
        //TEMP = S5(A) + ft(B,C,D) + E + Wt + Kt;
        //E = D; D = C; C = S30(B); B = A; A = TEMP;
        //一共有80次操作
        //Kt = 0x5A827999  (0 <= t <= 19)
//        Kt = 0x6ED9EBA1 (20 <= t <= 39)
//        Kt = 0x8F1BBCDC (40 <= t <= 59)
//        Kt = 0xCA62C1D6 (60 <= t <= 79)
        for(int i=0;i<=19;i++){
            int temp=s(tempabcde[0],5)
                    +f1(tempabcde[1],tempabcde[2],tempabcde[3])
                    +tempabcde[4]
                    +m[i]+0x5A827999;
            tempabcde[4]=tempabcde[3];
            tempabcde[3]=tempabcde[2];
            tempabcde[2]=s(tempabcde[1],30);
            tempabcde[1]=tempabcde[0];
            tempabcde[0]=temp;
        }
        for(int i=20;i<=39;i++){
            int temp=s(tempabcde[0],5)
                    +f2(tempabcde[1],tempabcde[2],tempabcde[3])
                    +tempabcde[4]
                    +m[i]+0x6ED9EBA1;
            tempabcde[4]=tempabcde[3];
            tempabcde[3]=tempabcde[2];
            tempabcde[2]=s(tempabcde[1],30);
            tempabcde[1]=tempabcde[0];
            tempabcde[0]=temp;
        }
        for(int i=40;i<=59;i++){
            int temp=s(tempabcde[0],5)
                    +f3(tempabcde[1],tempabcde[2],tempabcde[3])
                    +tempabcde[4]
                    +m[i]+0x8F1BBCDC;
            tempabcde[4]=tempabcde[3];
            tempabcde[3]=tempabcde[2];
            tempabcde[2]=s(tempabcde[1],30);
            tempabcde[1]=tempabcde[0];
            tempabcde[0]=temp;
        }
        for(int i=60;i<=79;i++){
            int temp=s(tempabcde[0],5)
                    +f4(tempabcde[1],tempabcde[2],tempabcde[3])
                    +tempabcde[4]
                    +m[i]+0xCA62C1D6;
            tempabcde[4]=tempabcde[3];
            tempabcde[3]=tempabcde[2];
            tempabcde[2]=s(tempabcde[1],30);
            tempabcde[1]=tempabcde[0];
            tempabcde[0]=temp;
        }
        //5.令 H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E.
        for(int i=0;i<tempabcde.length;i++){
            h[i]=h[i]+tempabcde[i];
        }
        //完成了一次操作
        //清除之前的内容,开始下一个块的计算
        for(int i=0;i<m.length;i++){
            m[i]=0;
        }

    }
    //把已经算好的数据提供一个接口进行输入和输出
    public static byte[] getDigestOfBytes(byte[] byteData){
        process_input_bytes(byteData);
        byte[] digest=new byte[20];
        for(int i=0;i<h.length;i++){
            intToByteArray(h[i],digest,i*4);
        }
        return digest;
    }
    public static String getDigestOfString(byte[] byteData){
        return byteArrayToHexString(getDigestOfBytes(byteData));
    }

    @Test
    public void test(){
        //ad93ae3d06a9114b3cbb33b6433ad546f0aa9f42
        //378940973d2f16265b7a7f2a78a253c45d953b0b
        String param="jeTt";
        System.out.println("加密前:"+param);
        String digest=getDigestOfString(param.getBytes());
        System.out.println("加密后的结果:"+digest);
    }

}