C# 里面封装的Aes算法好像跟网上C++的加密算法差很多。在网上找了很多资料才看到一个很早的文章, 用C#实现网上C++的算法。

http://msdn.microsoft.com/zh-cn/magazine/cc164055(en-us).aspx

using System;

namespace AesLib
{
  public class Aes  // Advanced Encryption Standard
  {
    public enum KeySize { Bits128, Bits192, Bits256 };  // key size, in bits, for construtor

private int Nb;         // block size in 32-bit words.  Always 4 for AES.  (128 bits).
    private int Nk;         // key size in 32-bit words.  4, 6, 8.  (128, 192, 256 bits).
    private int Nr;         // number of rounds. 10, 12, 14.

private byte[] key;     // the seed key. size will be 4 * keySize from ctor.
    private byte[,] Sbox;   // Substitution box
    private byte[,] iSbox;  // inverse Substitution box
    private byte[,] w;      // key schedule array.
    private byte[,] Rcon;   // Round constants.
    private byte[,] State;  // State matrix

public Aes(KeySize keySize, byte[] keyBytes)
    {
      SetNbNkNr(keySize);
 
      this.key = new byte[this.Nk * 4];  // 16, 24, 32 bytes
      keyBytes.CopyTo(this.key, 0);

BuildSbox();
      BuildInvSbox();
      BuildRcon();
      KeyExpansion();  // expand the seed key into a key schedule and store in w
 
    }  // Aes constructor

public void Cipher(byte[] input, byte[] output)  // encipher 16-bit input
    {
      // state = input
      this.State = new byte[4,Nb];  // always [4,4]
      for (int i = 0; i < (4 * Nb); ++i)
      {
        this.State[i % 4, i / 4] = input[i];
      }

AddRoundKey(0);
         
      for (int round = 1; round <= (Nr - 1); ++round)  // main round loop
      {
        SubBytes();
        ShiftRows(); 
        MixColumns();
        AddRoundKey(round);
      }  // main round loop

SubBytes();
      ShiftRows();
      AddRoundKey(Nr);
           
      // output = state
      for (int i = 0; i < (4 * Nb); ++i)
      {
        output[i] = this.State[i % 4, i / 4];
      }

}  // Cipher()

public void InvCipher(byte[] input, byte[] output)  // decipher 16-bit input
    {
      // state = input
      this.State = new byte[4,Nb];  // always [4,4]
      for (int i = 0; i < (4 * Nb); ++i)
      {
        this.State[i % 4, i / 4] = input[i];
      }

AddRoundKey(Nr);
     
      for (int round = Nr-1; round >= 1; --round)  // main round loop
      {
        InvShiftRows();
        InvSubBytes();
        AddRoundKey(round);
        InvMixColumns();
      }  // end main round loop for InvCipher

InvShiftRows();
      InvSubBytes();
      AddRoundKey(0);

// output = state
      for (int i = 0; i < (4 * Nb); ++i)
      {
        output[i] = this.State[i % 4, i / 4];
      }

}  // InvCipher()

private void SetNbNkNr(KeySize keySize)
    {
      this.Nb = 4;     // block size always = 4 words = 16 bytes = 128 bits for AES

if (keySize == KeySize.Bits128)
      {
        this.Nk = 4;   // key size = 4 words = 16 bytes = 128 bits
        this.Nr = 10;  // rounds for algorithm = 10
      }
      else if (keySize == KeySize.Bits192)
      {
        this.Nk = 6;   // 6 words = 24 bytes = 192 bits
        this.Nr = 12;
      }
      else if (keySize == KeySize.Bits256)
      {
        this.Nk = 8;   // 8 words = 32 bytes = 256 bits
        this.Nr = 14;
      }
    }  // SetNbNkNr()

private void BuildSbox()
    {
      this.Sbox = new byte[16,16] {  // populate the Sbox matrix
    /* 0     1     2     3     4     5     6     7     8     9     a     b     c     d     e     f */
    /*0*/  {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76},
    /*1*/  {0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0},
    /*2*/  {0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15},
    /*3*/  {0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75},
    /*4*/  {0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84},
    /*5*/  {0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf},
    /*6*/  {0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8},
    /*7*/  {0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2},
    /*8*/  {0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73},
    /*9*/  {0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb},
    /*a*/  {0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79},
    /*b*/  {0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08},
    /*c*/  {0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a},
    /*d*/  {0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e},
    /*e*/  {0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf},
    /*f*/  {0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16} };

}  // BuildSbox()

private void BuildInvSbox()
    {
      this.iSbox = new byte[16,16] {  // populate the iSbox matrix
    /* 0     1     2     3     4     5     6     7     8     9     a     b     c     d     e     f */
    /*0*/  {0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb},
    /*1*/  {0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb},
    /*2*/  {0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e},
    /*3*/  {0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25},
    /*4*/  {0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92},
    /*5*/  {0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84},
    /*6*/  {0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06},
    /*7*/  {0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b},
    /*8*/  {0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73},
    /*9*/  {0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e},
    /*a*/  {0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b},
    /*b*/  {0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4},
    /*c*/  {0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f},
    /*d*/  {0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef},
    /*e*/  {0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61},
    /*f*/  {0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d} };

}  // BuildInvSbox()

private void BuildRcon()
    {
      this.Rcon = new byte[11,4] { {0x00, 0x00, 0x00, 0x00}, 
                                   {0x01, 0x00, 0x00, 0x00},
                                   {0x02, 0x00, 0x00, 0x00},
                                   {0x04, 0x00, 0x00, 0x00},
                                   {0x08, 0x00, 0x00, 0x00},
                                   {0x10, 0x00, 0x00, 0x00},
                                   {0x20, 0x00, 0x00, 0x00},
                                   {0x40, 0x00, 0x00, 0x00},
                                   {0x80, 0x00, 0x00, 0x00},
                                   {0x1b, 0x00, 0x00, 0x00},
                                   {0x36, 0x00, 0x00, 0x00} };
    }  // BuildRcon()

private void AddRoundKey(int round)
    {

for (int r = 0; r < 4; ++r)
      {
        for (int c = 0; c < 4; ++c)
        {
          this.State[r,c] = (byte) ( (int)this.State[r,c] ^ (int)w[(round*4)+c,r] );
        }
      }
    }  // AddRoundKey()

private void SubBytes()
    {
      for (int r = 0; r < 4; ++r)
      {
        for (int c = 0; c < 4; ++c)
        {
          this.State[r,c] = this.Sbox[ (this.State[r,c] >> 4), (this.State[r,c] & 0x0f) ];
        }
      }
    }  // SubBytes

private void InvSubBytes()
    {
      for (int r = 0; r < 4; ++r)
      {
        for (int c = 0; c < 4; ++c)
        {
          this.State[r,c] = this.iSbox[ (this.State[r,c] >> 4), (this.State[r,c] & 0x0f) ];
        }
      }
    }  // InvSubBytes

private void ShiftRows()
    {
      byte[,] temp = new byte[4,4];
      for (int r = 0; r < 4; ++r)  // copy State into temp[]
      {
        for (int c = 0; c < 4; ++c)
        {
          temp[r,c] = this.State[r,c];
        }
      }

for (int r = 1; r < 4; ++r)  // shift temp into State
      {
        for (int c = 0; c < 4; ++c)
        {
          this.State[r,c] = temp[ r, (c + r) % Nb ];
        }
      }
    }  // ShiftRows()

private void InvShiftRows()
    {
      byte[,] temp = new byte[4,4];
      for (int r = 0; r < 4; ++r)  // copy State into temp[]
      {
        for (int c = 0; c < 4; ++c)
        {
          temp[r,c] = this.State[r,c];
        }
      }
      for (int r = 1; r < 4; ++r)  // shift temp into State
      {
        for (int c = 0; c < 4; ++c)
        {
          this.State[r, (c + r) % Nb ] = temp[r,c];
        }
      }
    }  // InvShiftRows()

private void MixColumns()
    {
      byte[,] temp = new byte[4,4];
      for (int r = 0; r < 4; ++r)  // copy State into temp[]
      {
        for (int c = 0; c < 4; ++c)
        {
          temp[r,c] = this.State[r,c];
        }
      }
       
      for (int c = 0; c < 4; ++c)
      {
        this.State[0,c] = (byte) ( (int)gfmultby02(temp[0,c]) ^ (int)gfmultby03(temp[1,c]) ^
                                   (int)gfmultby01(temp[2,c]) ^ (int)gfmultby01(temp[3,c]) );
        this.State[1,c] = (byte) ( (int)gfmultby01(temp[0,c]) ^ (int)gfmultby02(temp[1,c]) ^
                                   (int)gfmultby03(temp[2,c]) ^ (int)gfmultby01(temp[3,c]) );
        this.State[2,c] = (byte) ( (int)gfmultby01(temp[0,c]) ^ (int)gfmultby01(temp[1,c]) ^
                                   (int)gfmultby02(temp[2,c]) ^ (int)gfmultby03(temp[3,c]) );
        this.State[3,c] = (byte) ( (int)gfmultby03(temp[0,c]) ^ (int)gfmultby01(temp[1,c]) ^
                                   (int)gfmultby01(temp[2,c]) ^ (int)gfmultby02(temp[3,c]) );
      }
    }  // MixColumns

private void InvMixColumns()
    {
      byte[,] temp = new byte[4,4];
      for (int r = 0; r < 4; ++r)  // copy State into temp[]
      {
        for (int c = 0; c < 4; ++c)
        {
          temp[r,c] = this.State[r,c];
        }
      }
       
      for (int c = 0; c < 4; ++c)
      {
        this.State[0,c] = (byte) ( (int)gfmultby0e(temp[0,c]) ^ (int)gfmultby0b(temp[1,c]) ^
                                   (int)gfmultby0d(temp[2,c]) ^ (int)gfmultby09(temp[3,c]) );
        this.State[1,c] = (byte) ( (int)gfmultby09(temp[0,c]) ^ (int)gfmultby0e(temp[1,c]) ^
                                   (int)gfmultby0b(temp[2,c]) ^ (int)gfmultby0d(temp[3,c]) );
        this.State[2,c] = (byte) ( (int)gfmultby0d(temp[0,c]) ^ (int)gfmultby09(temp[1,c]) ^
                                   (int)gfmultby0e(temp[2,c]) ^ (int)gfmultby0b(temp[3,c]) );
        this.State[3,c] = (byte) ( (int)gfmultby0b(temp[0,c]) ^ (int)gfmultby0d(temp[1,c]) ^
                                   (int)gfmultby09(temp[2,c]) ^ (int)gfmultby0e(temp[3,c]) );
      }
    }  // InvMixColumns

private static byte gfmultby01(byte b)
    {
      return b;
    }

private static byte gfmultby02(byte b)
    {
      if (b < 0x80)
        return (byte)(int)(b <<1);
      else
        return (byte)( (int)(b << 1) ^ (int)(0x1b) );
    }

private static byte gfmultby03(byte b)
    {
      return (byte) ( (int)gfmultby02(b) ^ (int)b );
    }

private static byte gfmultby09(byte b)
    {
      return (byte)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^
                     (int)b );
    }

private static byte gfmultby0b(byte b)
    {
      return (byte)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^
                     (int)gfmultby02(b) ^
                     (int)b );
    }

private static byte gfmultby0d(byte b)
    {
      return (byte)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^
                     (int)gfmultby02(gfmultby02(b)) ^
                     (int)(b) );
    }

private static byte gfmultby0e(byte b)
    {
      return (byte)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^
                     (int)gfmultby02(gfmultby02(b)) ^
                     (int)gfmultby02(b) );
    }

private void KeyExpansion()
    {
      this.w = new byte[Nb * (Nr+1), 4];  // 4 columns of bytes corresponds to a word
   
      for (int row = 0; row < Nk; ++row)
      {
        this.w[row,0] = this.key[4*row];
        this.w[row,1] = this.key[4*row+1];
        this.w[row,2] = this.key[4*row+2];
        this.w[row,3] = this.key[4*row+3];
      }

byte[] temp = new byte[4];

for (int row = Nk; row < Nb * (Nr+1); ++row)
      {
        temp[0] = this.w[row-1,0]; temp[1] = this.w[row-1,1];
        temp[2] = this.w[row-1,2]; temp[3] = this.w[row-1,3];

if (row % Nk == 0) 
        {
          temp = SubWord(RotWord(temp));
         
          temp[0] = (byte)( (int)temp[0] ^ (int)this.Rcon[row/Nk,0] );
          temp[1] = (byte)( (int)temp[1] ^ (int)this.Rcon[row/Nk,1] );
          temp[2] = (byte)( (int)temp[2] ^ (int)this.Rcon[row/Nk,2] );
          temp[3] = (byte)( (int)temp[3] ^ (int)this.Rcon[row/Nk,3] );
        }
        else if ( Nk > 6 && (row % Nk == 4) ) 
        {
          temp = SubWord(temp);
        }
       
        // w[row] = w[row-Nk] xor temp
        this.w[row,0] = (byte) ( (int)this.w[row-Nk,0] ^ (int)temp[0] );
        this.w[row,1] = (byte) ( (int)this.w[row-Nk,1] ^ (int)temp[1] );
        this.w[row,2] = (byte) ( (int)this.w[row-Nk,2] ^ (int)temp[2] );
        this.w[row,3] = (byte) ( (int)this.w[row-Nk,3] ^ (int)temp[3] );
      
      }  // for loop
    }  // KeyExpansion()

private byte[] SubWord(byte[] word)
    {
      byte[] result = new byte[4];
      result[0] = this.Sbox[ word[0] >> 4, word[0] & 0x0f ];
      result[1] = this.Sbox[ word[1] >> 4, word[1] & 0x0f ];
      result[2] = this.Sbox[ word[2] >> 4, word[2] & 0x0f ];
      result[3] = this.Sbox[ word[3] >> 4, word[3] & 0x0f ];
      return result;
    }

private byte[] RotWord(byte[] word)
    {
      byte[] result = new byte[4];
      result[0] = word[1];
      result[1] = word[2];
      result[2] = word[3];
      result[3] = word[0];
      return result;
    }

public  void Dump()
    {
      Console.WriteLine("Nb = " + Nb + " Nk = " + Nk + " Nr = " + Nr);
      Console.WriteLine("\nThe key is \n" + DumpKey() );
      Console.WriteLine("\nThe Sbox is \n" + DumpTwoByTwo(Sbox));
      Console.WriteLine("\nThe w array is \n" + DumpTwoByTwo(w));
      Console.WriteLine("\nThe State array is \n" + DumpTwoByTwo(State));
    }

public string DumpKey()
    {
      string s = "";
      for (int i = 0; i < key.Length; ++i)
        s += key[i].ToString("x2") + " ";
      return s;
    }

public string DumpTwoByTwo(byte[,] a)
    {
      string s ="";
      for (int r = 0; r < a.GetLength(0); ++r)
      {
        s += "["+r+"]" + " ";
        for (int c = 0; c < a.GetLength(1); ++c)
        {
          s += a[r,c].ToString("x2") + " " ;
        }
        s += "\n";
      }
      return s;
    }

}  // class Aes
}  // ns AesLib

AES 加密问题的更多相关文章

  1. 关于CryptoJS中md5加密以及aes加密的随笔

    最近项目中用到了各种加密,其中就包括从没有接触过得aes加密,因此从网上各种查,官方的一种说法: 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学 ...

  2. AES加密

    package com.edu.hpu; import java.math.BigInteger; import java.security.MessageDigest; import java.se ...

  3. Android数据加密之Aes加密

    前言: 项目中除了登陆,支付等接口采用rsa非对称加密,之外的采用aes对称加密,今天我们来认识一下aes加密. 其他几种加密方式: Android数据加密之Rsa加密 Android数据加密之Aes ...

  4. c#和js互通的AES加密解密

    一.使用场景 在使用前后端分离的框架中常常会进行传输数据相互加密解密以确保数据的安全性,如web Api返回加密数据客户端或web端进行解密,或者客户端或web端进行加密提交数据服务端解密数据等等. ...

  5. AES加密解密通用版Object-C / C# / JAVA

    1.无向量 128位 /// <summary> /// AES加密(无向量) /// </summary> /// <param name="plainByt ...

  6. nodejs与javascript中的aes加密

    简介 1.aes加密简单来说,在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用.高级加密标准已然成为对称密钥加 ...

  7. 非对称技术栈实现AES加密解密

    非对称技术栈实现AES加密解密 正如前面的一篇文章所述,https协议的SSL层是实现在传输层之上,应用层之下,也就是说在应用层上看到的请求还是明码的,对于某些场景下要求这些http请求参数是非可读的 ...

  8. Java aes加密C#解密的取巧方法

    摘要: 项目开发过程中遇到一个棘手的问题:A系统使用java开发,通过AES加密数据,B系统使用C#开发,需要从A系统获取数据,但在AES解密的时候遇到麻烦.Java的代码和C#的代码无法互通. Ja ...

  9. AES 加密工具类

    /** * AES 是一种可逆加密算法,对用户的敏感信息加密处理 对原始数据进行AES加密后,在进行Base64编码转化: */public class AESOperator { /* * 加密用的 ...

  10. android base64 和 aes 加密 解密

    package pioneerbarcode.ccw.com.encryptanddecode;import android.os.Bundle;import android.support.v7.a ...

随机推荐

  1. IntelliJ Idea 配置Tomcat提示Port is not specified

    修改Debug这里的端口就好了

  2. spring的4种事务特性,5种隔离级别,7种传播行为

    spring事务:  事务: 事务逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败. 事务特性(4种): 原子性 (atomicity):强调事务的不可分割. 一致性 (con ...

  3. Java-把日期字符串转换成另一种格式的日期字符串

    package com.example.demo.utils; import java.text.ParseException; import java.text.SimpleDateFormat; ...

  4. [bzoj3522][bzoj4543][POI2014]HOTEL

    题解: 比较难的一道题目 首先考虑暴力dp 我们会发现构成这种形状只有三种情况 1.三个点的lca相同 2.两个点lca相同,第三个点是lca的祖先 3.两个点lca相同,第三个点是lca祖先的子树中 ...

  5. java抽象类详解

    前言 在没讲抽象类之前  我们先来看看 final关键字 final 修饰符 可以修饰 类.属性.方法 修饰类时  表示该类不能被继承   其他特征 跟普通的类一样 修饰 属性时 表示 改属性不能改变 ...

  6. 【AtCoder】ExaWizards 2019

    ExaWizards 2019 C - Snuke the Wizard 发现符文的相对位置不变,直接二分某个位置是否到达最左或最右来计算 #include <bits/stdc++.h> ...

  7. Docker数据卷和Docker系统管理(一)

    一. 创建和挂载数据卷 1. 创建数据卷 (1)执行下列命令,创建一个名为my-data的数据卷 [root@c720120 ~]# docker volume create my-data my-d ...

  8. day40 mycql 视图,触发器,存储过程,函数

    视图,触发器,存储过程,自定义函数 -- 回顾 1.mysql 约束 1.非空 not null 2. 主键约束 primary key 3. 唯一约束 unique 4. 外键约束 foreign ...

  9. QT +go 开发 GUI程序

      ,转载 https://blog.csdn.net/lanbery/article/details/81745611 如果你是一个墨守成规的coding,请移步其他内容,这部分内容可能不适合你.如 ...

  10. PostgreSQL 创建触发器 Trigger

    触发器的知识点: PostgreSQL在以下情况下执行/调用触发器:在尝试操作之前(在检查约束并尝试INSERT,UPDATE或DELETE之前).或者在操作完成后(在检查约束并且INSERT,UPD ...