常见实用算法总结

  最近难得有空,整理了一下以前项目中用到的一些常见算法,从原理入手,深入浅出讲解,并给出每个算法的实现,对开拓思维还是很有帮助的,同大家一起分享,有不对之处欢迎一起讨论。

  1. 快速排序
  2. 快速幂算法
  3. 斐波那契数列
  4. 异或算法
  5. Base64编码/解码算法
  6. CRC16算法
  7. SHA256算法

 

  1. 快速排序

  快速排序(Quicksort)是对冒泡排序的一种改进,由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

 1 int partition(int sortArray[], int low, int height)
 2 {
 3     int key = sortArray[low]; // 刚开始以第一个数为标志数据
 4     while (low < height)
 5     {
 6         // 从后面开始找,找到比key值小的数为止
 7         while (low < height && sortArray[height] >= key)
 8             height--;
 9         sortArray[low] = sortArray[height]; // 将该数放到key值的左边
10         
11         // 从前面开始找,找到比key值大的数为止
12         while (low < height && sortArray[low] <= key)
13             low++;
14         sortArray[height] = sortArray[low]; // 将该数放到key值的右边
15     }
16     sortArray[low] = key; // 把key值填充到low位置,下次重新找key值
17 }
18 
19 void sort(int sortArray[], int low, int height)
20 {
21     if  (low < height)
22     {
23         int  result = partition(sortArray, low, height);
24         sort(sortArray, low, result - 1);
25         sort(sortArray, result + 1, height);
26     }
27 }

  另外,与快速排序效率接近或更高的排序算法有:归并排序、希尔排序、堆排序、计数排序等,这里就不一 一介绍了,感兴趣可以查看连接:https://zhuanlan.zhihu.com/p/40695917

  2. 快速幂算法

  Quick Power 核心思想是:利用二进制来大幅减少循环次数,加速运算。具体可以用一句话概括 “指数折半,底数变其平方”。这种思想在降低循环次数有很大的启迪。

  根据指数运算规则:nm + k = nm * nk、nm= ( n)K、n-m = 1/nm、n= 1 ,下面来举例说明:

  求 3^5 我们可以将指数 5 用二进制来表示 101b = 2^2 + 2^0 ,3^5 = 3^(2^2 + 2^0) = 3^(2^2) * 3(2^0) = (3^2)^2 * 3 = 9^2 * 3 = 243

 1 // 通常的实现
 2 double power(float base, int power)
 3 {
 4     double result = 1;
 5     
 6     if (power > 0)
 7     {
 8         for (int i = 0; i < power; i++)
 9             result *= base;
10     }
11     else
12     {
13         for (int i = 0; i > power; i--)
14             result /= base;
15     }
16 
17     return result;
18 }
19 
20 // 快速幂实现
21 double quick_power(float base, int power)
22 {
23     double result = 1;
24     
25     if (power > 0)
26     {
27         while (power > 0)
28         {
29             if (power & 1)        // 指数为奇数
30                 result *= base;   // 分离出当前项并累乘后保存
31             power >>= 1;          // 指数折半
32             base *= base;         // 底数变其平方
33         }
34     }
35     else
36     {
37         while (power < 0)
38         {
39             if (power & 1)        // 指数为奇数
40                 result /= base;   // 分离出当前项并累除后保存
41             power >>= 1;          // 指数折半
42             base *= base;         // 底数变其平方
43         }
44     }
45     
46     return result;
47 }

  3. 斐波那契数列

  斐波那契数列:0,1,1,2,3,5,8,13,...

  斐波那契数列的递推公式为:F(n) = F(n-1) + F(n-2),其中F(0) = 0,F(1) = 1,n > 1

1 long int fib(unsigned int n) 
2 {
3   return (n <= 1) ? n : fib(n-1) + fib(n-2);
4 }

   当 n 比较大时,如何使用快速幂思想来降低循环次数呢 ?是不是有点意思,可以思考一下。

  4. 异或算法

  异或算法利用其自生的自反性常用于加密领域,即 A xor B xor B = A,特点是算法简单,容易实现,加密和解密函数同体。通常经过几轮异或后,密文早已物是人非,很难被破解了。

1 // 将密钥key按位与密文text异或,key长度不够时,从头开始,直到text每一位与key异或完
2 void xorEncode(const std::string key, std::string text)
3 {
4     for (unsigned int i = 0; i < text.size(); i++)
5     {
6         text[ i ] ^= key[ i % key.size() ];
7     }
8 }

  5. Base64编码/解码算法

  Base64只是一种编码方法,其原理是将数据按6位一组进行编码,从Base64字符表中取对应的字符,将原字符转换为新的字符来表示,其优点是编码后字符可见,便于查看和传递,但是数据长度会变为原来的4/3,经常与加密数据或者网络传输时结合使用。下面以字符串 “shuai” 举例说明:

  

  下面编/解码以3字节为一组,每6位进行编码(3字节24位,可以编码4个Base64字符),将6位数值作为数组下标从Base64字符集中取对应的字符,组成新的字符串。

  1 const std::string base64_chars = 
  2     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";  3 
  4 std::string base64Encode(const std::string& text)
  5 {
  6     std::string encoded;
  7     int i = 0,j = 0;
  8     unsigned char decode[3];  // 三字节为一组进行编码
  9     unsigned char charat[4];  // 保存base64字符位置
 10 
 11     for (const auto& ch : text)
 12     {
 13         decode[i++] = ch;
 14 
 15         if (i == 3)
 16         {
 17             charat[0] = ((decode[0] & 0xfc) >> 2);
 18             charat[1] = ((decode[0] & 0x03) << 4) + ((decode[1] & 0xf0) >> 4);
 19             charat[2] = ((decode[1] & 0x0f) << 2) + ((decode[2] & 0xc0) >> 6);
 20             charat[3] = decode[2] & 0x3f;
 21 
 22             for (i = 0; i < 4; i++) {
 23                 encoded += base64_chars[charat[i]];
 24             }
 25 
 26             i = 0;
 27         }
 28     }
 29 
 30     if (i > 0)
 31     {
 32         for (j = i; j < 3; j++) {
 33             decode[j] = '\0';
 34         }
 35 
 36         charat[0] = ((decode[0] & 0xfc) >> 2);
 37         charat[1] = ((decode[0] & 0x03) << 4) + ((decode[1] & 0xf0) >> 4);
 38         charat[2] = ((decode[1] & 0x0f) << 2) + ((decode[2] & 0xc0) >> 6);
 39         charat[3] = decode[2] & 0x3f;
 40 
 41         for (j = 0; j < i + 1; j++) {
 42             encoded += base64_chars[charat[j]];
 43         }
 44 
 45         while (i++ < 3) {
 46             encoded += '=';
 47         }
 48     }
 49 
 50     return encoded;
 51 }
 52 
 53 std::string base64Decode(const std::string& text)
 54 {
 55     std::string decoded;
 56     
 57     int i = 0, j = 0;
 58     unsigned char decode[3];  // 三字节为一组进行解码
 59     unsigned char charat[4];  // 保存base64字符位置
 60 
 61     for (const auto& ch : text) {
 62         if ('=' == ch) {
 63             break;
 64         }
 65 
 66         charat[i++] = ch;
 67 
 68         if (i == 4) 
 69         {
 70             for (i = 0; i < 4; i++) {
 71                 charat[i] = base64_chars.find(charat[i]);
 72             }
 73 
 74             decode[0] = (charat[0] << 2) + ((charat[1] & 0x30) >> 4);
 75             decode[1] = ((charat[1] & 0xf) << 4) + ((charat[2] & 0x3c) >> 2);
 76             decode[2] = ((charat[2] & 0x3) << 6) + charat[3];
 77 
 78             for (i = 0; i < 3; i++) {
 79                 decoded += decode[i];
 80             }
 81 
 82             i = 0;
 83         }
 84     }
 85 
 86     if (i > 0) 
 87     {
 88         for (j = i; j < 4; j++) {
 89             charat[j] = 0;
 90         }
 91 
 92         for (j = 0; j < 4; j++) {
 93             charat[j] = base64_chars.find(charat[j]);
 94         }
 95 
 96         decode[0] = (charat[0] << 2) + ((charat[1] & 0x30) >> 4);
 97         decode[1] = ((charat[1] & 0xf) << 4) + ((charat[2] & 0x3c) >> 2);
 98         decode[2] = ((charat[2] & 0x3) << 6) + charat[3];
 99 
100         for (j = 0; j < i - 1; j++) {
101             decoded += decode[j];
102         }
103     }
104 
105     return decoded;
106 }

  6. CRC16算法

  CRC(Cyclic Redundancy Check):循环冗余校验,是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。CRC是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。

  这篇文章讲得比较通透,想进一步了解可点击查阅:https://www.cnblogs.com/dl610455894/p/14442018.html

  下面给出CRC16一种查表法的实现:

 1 static const uint16_t crc16tab[256]= {
 2     0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
 3     0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
 4     0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
 5     0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
 6     0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
 7     0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
 8     0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
 9     0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
10     0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
11     0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
12     0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
13     0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
14     0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
15     0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
16     0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
17     0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
18     0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
19     0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
20     0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
21     0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
22     0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
23     0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
24     0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
25     0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
26     0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
27     0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
28     0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
29     0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
30     0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
31     0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
32     0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
33     0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
34 };
35 
36 uint16_t crc16(const char *buf, int len)
37 {
38     uint16_t crc = 0;
39     for (int counter = 0; counter < len; counter++)
40             crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++)&0x00FF];
41     return crc;
42 }

  7. SHA256算法

  关于SHA256介绍可参考 https://www.cnblogs.com/Tenfei/articles/14283340.html

 

本文作者:博客园博主 KeepHopes,对大数据、人工智能领域颇感兴趣,请多多赐教!
原文链接:https://www.cnblogs.com/yuwanxian/p/17681503.html
版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 4.0许可协议。转载请注明出处,谢谢!
posted @ 2023-09-07 17:56  ywx-super  阅读(20)  评论(0编辑  收藏  举报