zoukankan      html  css  js  c++  java
  • 【编程珠玑】读书笔记 第二章 算法

    2013-07-11 22:00:28

    第二章 算法

    本章围绕三个问题进行算法讨论,包括元素的查找、字符串的旋转、以及变位词的查找。

    下面给出了实现代码、以及测试结果。

    问题一 查找不存在的元素

    思路一:用位图;

    思路二:用二分搜索法,这种方法需要先对数组排序;

    若用二分搜索法,有以下限制:

    满足以下假设:
    1)数组中没有重复元素
    2)数组中必有缺失元素

    书中给出的问题也正是具有这样的特殊性,因此可以使用二分法进行缺失元素的查找。

    下面的代码给出了上述两种方法的实现代码,以及测试代码所需要的数据产生程序、位图排序程序,后面附上了测试结果。

    注意:此处的代码没有数据的合法性检查,假设数据满足上面的条件。

    完整代码:

      1 #include <iostream>
      2 #include <bitset>
      3 #include <ctime>
      4 using namespace std;
      5 
      6 const int MAX_NUMBER = 10000010;
      7 const int NUMBER_OF_DATA = 10000000;
      8 
      9 //产生在区间[lowerBound,upperBound]内的一个随机数
     10 int RandomInt(const int lowerBound,const int upperBound)
     11 {
     12     return ( lowerBound + ( RAND_MAX * rand() + rand() ) % (upperBound - lowerBound + 1) );
     13 }
     14 
     15 //产生在[0,maxOfRandomInt]范围内的numberOfRandomInt个随机数
     16 //结果存入数组randomInt中
     17 void RandomIntGen(const int numberOfRandomInt,const int maxOfRandomInt,int randomInt[])
     18 {
     19     int i;
     20     int tmp;
     21     int randomTmp;
     22     int *sequenceInt = new int[maxOfRandomInt];
     23 
     24     srand((unsigned) time(NULL));
     25 
     26     for (i = 0; i < maxOfRandomInt; i++)
     27     {
     28         sequenceInt[i] = i;    
     29     }
     30 
     31     for (i = 0; i < numberOfRandomInt; i++) 
     32     {
     33         randomTmp = RandomInt(i, maxOfRandomInt - 1);
     34         tmp = sequenceInt[randomTmp];
     35         sequenceInt[randomTmp] = sequenceInt[i];
     36         sequenceInt[i] = tmp;
     37         randomInt[i] = sequenceInt[i];    //随机数保存在数组中
     38     }
     39 
     40     delete [] sequenceInt;   //释放内存
     41 }
     42 
     43 //注意写初始化函数
     44 void Init(int BitmapArray[],const int n)
     45 {
     46     for (int i = 0;i < n;++i)
     47     {
     48         BitmapArray[i] = 0;
     49     }
     50 }
     51 
     52 //用int型模拟位图,实现的位图排序
     53 const int BitsPerInt = 32;
     54 const int Div32Shift = 5;
     55 const int Mod32Mask = 0x1F;
     56 
     57 //BitmapSort_2:用位运算实现置位、清零、判断是否为1
     58 void SetBit(int BitmapArray[],const int BitToSet)
     59 {
     60     //BitmapArray[ (BitToSet >> Div32Shift) ] | = ( 1 << (BitToSet & Mod32Mask) );  //error C2059: syntax error : '='
     61     BitmapArray[ (BitToSet >> Div32Shift) ] = BitmapArray[ (BitToSet >> Div32Shift) ] 
     62     | ( 1 << (BitToSet & Mod32Mask) ); 
     63 }
     64 
     65 void ClearBit(int BitmapArray[],const int BitToClear)
     66 {
     67     BitmapArray[ (BitToClear >> Div32Shift) ] = BitmapArray[ (BitToClear >> Div32Shift) ] 
     68     & ~( 1 << (BitToClear & Mod32Mask) ); 
     69 }
     70 
     71 bool IsBitSet(const int BitmapArray[],const int BitToCheck)  //定义为const类型,在不小心改变时,会给出报错信息
     72 {
     73     return ( BitmapArray[ (BitToCheck >> Div32Shift) ] & ( 1 << (BitToCheck & Mod32Mask) ) ); 
     74 }
     75 
     76 void BitmapSort_2(int ArrayUnsorted[],const int n)
     77 {
     78     int i ;
     79     int cnt = 0;
     80     int *BitmapArray = new int[1 + MAX_NUMBER/BitsPerInt];   //当MaxRandomInt较大时,必须从对上分配内存,否则内存不够用,导致出错
     81 
     82     if (NULL == BitmapArray)
     83     {
     84         cout<<"memory allocation error !"<<endl;
     85         exit(0);
     86     }
     87 
     88     Init(BitmapArray,1 + MAX_NUMBER/BitsPerInt);   //初始化为0
     89 
     90     for (i = 0;i < n;++i)
     91     {
     92         SetBit(BitmapArray,ArrayUnsorted[i]);
     93     }
     94 
     95     for (i = 0;i < MAX_NUMBER;++i)  //不是for (i = 0;i < n;++i)
     96     {
     97         if ( IsBitSet(BitmapArray,i) )
     98         {
     99             ArrayUnsorted[cnt++] = i;
    100         }
    101     }
    102 
    103     delete [] BitmapArray;
    104 }
    105 
    106 //用位图的方法查找丢失元素
    107 //满足以下假设:
    108 //1)数组中没有重复元素
    109 //2)数组中必有缺失元素
    110 int FindLostByBitmap(int arrayToFind[],int numberOfData)
    111 {
    112     int i ;
    113     int cnt = 0;
    114     int *BitmapArray = new int[1 + MAX_NUMBER/BitsPerInt];   //当MaxRandomInt较大时,必须从对上分配内存,否则内存不够用,导致出错
    115 
    116     if (NULL == BitmapArray)
    117     {
    118         cout<<"memory allocation error !"<<endl;
    119         exit(0);
    120     }
    121 
    122     Init(BitmapArray,1 + MAX_NUMBER/BitsPerInt);   //初始化为0
    123 
    124     for (i = 0;i < numberOfData;++i)
    125     {
    126         SetBit(BitmapArray,arrayToFind[i]);
    127     }
    128 
    129     for (i = 0;i < MAX_NUMBER;++i)  //不是for (i = 0;i < n;++i)
    130     {
    131         if ( !IsBitSet(BitmapArray,i) )
    132         {
    133             return i;
    134         }
    135     }
    136 
    137     if (MAX_NUMBER == i)
    138     {
    139         cout<<"no element is lost!"<<endl;
    140         return -1;
    141     }
    142 
    143     delete [] BitmapArray;
    144 }
    145 
    146 //二分搜索法
    147 //满足以下假设:
    148 //1)数组中没有重复元素
    149 //2)数组中必有缺失元素
    150 int FindLostByBinarySearch(int arrayToFind[],int numberOfData)
    151 {
    152     int cnt = 0;
    153     int begin  = 0;
    154     int end = numberOfData - 1;
    155     int mid = 0;
    156 
    157     if (NULL == arrayToFind || numberOfData < 2)
    158     {
    159         cout<<"the input array is invalid!"<<endl;
    160         return -1;
    161     }
    162 
    163     while (begin < end - 1)
    164     {
    165         mid = (begin + end)/2;
    166         if (arrayToFind[mid] - arrayToFind[begin] > mid - begin)
    167         {
    168             end = mid;
    169         }
    170         else
    171         {
    172             begin = mid;
    173         }
    174     }
    175 
    176     if (arrayToFind[end] - arrayToFind[begin] > 1)
    177     {  
    178         return (arrayToFind[begin] + 1);
    179     }
    180     else 
    181     {
    182         cout<<"no element is lost!"<<endl;
    183         return -1;
    184     }
    185 }
    186 
    187 //将数组写入txt中,便于检查结果的正确性
    188 void WriteArrayToUnsortedTxt(int array[],int n)
    189 {
    190     FILE *fout;
    191     int i;
    192 
    193     fout = fopen("array_unsorted.txt","wt");
    194 
    195     if(fout == NULL)
    196     {
    197         printf("forward_i.txt open error!
    ");
    198         exit(0);
    199     }
    200 
    201     printf("file open success!
    ");
    202 
    203     for (i = 0;i < n;i++) 
    204     {
    205         fprintf(fout,"%d
    ",array[i]);
    206     }
    207 
    208     fclose(fout);    
    209 }
    210 
    211 //将数组写入txt中,便于检查结果的正确性
    212 void WriteArrayToSortedTxt(int array[],int n)
    213 {
    214     FILE *fout;
    215     int i;
    216 
    217     fout = fopen("array_sorted.txt","wt");
    218 
    219     if(fout == NULL)
    220     {
    221         printf("forward_i.txt open error!
    ");
    222         exit(0);
    223     }
    224 
    225     printf("file open success!
    ");
    226 
    227     for (i = 0;i < n;i++) 
    228     {
    229         fprintf(fout,"%d
    ",array[i]);
    230     }
    231 
    232     fclose(fout);    
    233 }
    234 
    235 //显示数组元素
    236 void DisplayArray(int ArrayUnsorted[],int n)
    237 {
    238     for (int i = 0;i < n;++i)
    239     {
    240         cout<<ArrayUnsorted[i]<<"	";
    241     }
    242     cout<<endl;
    243 }
    244 
    245 //测试代码
    246 int main(void)
    247 {
    248     const int numberOfData = NUMBER_OF_DATA;
    249     const int maxOfRandomInt = MAX_NUMBER;
    250     int *arrayToFind = new int[NUMBER_OF_DATA];
    251     int StartTime = 0;
    252     int TimeCost = 0; 
    253 
    254     cout<<"the max number of integer is : "<<maxOfRandomInt<<endl;
    255     cout<<"the number of integer is : "<<numberOfData<<endl;
    256 
    257     RandomIntGen(numberOfData,maxOfRandomInt,arrayToFind);
    258     WriteArrayToUnsortedTxt(arrayToFind,numberOfData);
    259     /*cout<<"the randomInt array is :"<<endl;
    260     DisplayArray(arrayToFind,numberOfData);*/
    261     
    262     //Test FindLostByBitmap
    263     cout<<"Test FindLostByBitmap..."<<endl;
    264     StartTime = clock();
    265     cout<<"the lost number is : "<<FindLostByBitmap(arrayToFind,numberOfData)<<endl;
    266     TimeCost = 1e6 * ( clock() - StartTime ) / CLOCKS_PER_SEC;
    267     cout<<"the time cost of FindLostByBitmap is : "<<TimeCost<<"ms"<<endl;
    268 
    269     //BitmapSort_2,为使用基于二分法的搜索进行排序的预处理
    270     cout<<"Test BitmapSort_2..."<<endl;
    271 
    272     StartTime = clock();
    273     BitmapSort_2(arrayToFind,numberOfData);
    274     TimeCost = 1e6 * ( clock() - StartTime ) / CLOCKS_PER_SEC;
    275     cout<<"the time cost of BitmapSort_2 is : "<<TimeCost<<"ms"<<endl;
    276 
    277     WriteArrayToSortedTxt(arrayToFind,numberOfData);
    278     /*cout<<"the sorted array is : "<<endl;
    279     DisplayArray(arrayToFind,numberOfData);  */
    280 
    281     //Test FindLostByBinarySearch
    282     cout<<"Test FindLostByBinarySearch..."<<endl;
    283     StartTime = clock();
    284     cout<<"the lost number is : "<<FindLostByBinarySearch(arrayToFind,numberOfData)<<endl;
    285     TimeCost = 1e6 * ( clock() - StartTime ) / CLOCKS_PER_SEC;
    286     cout<<"the time cost of FindLostByBinarySearch is : "<<TimeCost<<"ms"<<endl;
    287 
    288     delete [] arrayToFind;   //delete与new要配对出现
    289     return 0;
    290 }

    测试结果,1000,0010个数据中缺失10个时:

    (可见,在该规模下,用二分搜索法的速度约为位图法的1000+倍)

    the max number of integer is : 10000010
    the number of integer is : 10000000
    file open success!
    Test FindLostByBitmap...
    the lost number is : 7952
    the time cost of FindLostByBitmap is : 1486000ms
    Test BitmapSort_2...
    the time cost of BitmapSort_2 is : 2078000ms
    file open success!
    Test FindLostByBinarySearch...
    the lost number is : 7952
    the time cost of FindLostByBinarySearch is : 8000ms
    请按任意键继续. . .

    上面的结果只是程序运行一次的结果,如果要得到比较靠靠的分析,应该多次测试,而且测试的结果可能与数据集有关,若要固定数据集,将随机数产生函数RandomIntGen中的//srand((unsigned) time(NULL));注释掉即可。


    问题二 数组的旋转

    对于该问题,大多数人都能想到比较直观的解决方法,书中已有说明,此处不再赘述,另外,书中给出了一种比较巧妙的解法,称为杂技法,并给出了代码实现,但对于该方法的原理没有介绍,杂技法不易理解,此处暂时不做讨论。


    问题三 变位词的查找

    可借助于[标识,单词]对,将变位词进行标识,根据标识划分变位词。

    借助于C++的工具vector、以及map,可以方便地实现。

    注意几点:

    1. 数据结构的选择,存储单词采用 vector <string> ,因为每个单词是string类型 ;
    2. 存储[标识,单词],采用map < string ,vector <string> >,因为一个标识sign对应多个string类型的单词;
    3. 标识通过对单词的排序得到,此处采用C++的排序函数sort,sort( sign.begin(),sign.end() );

    完整代码如下:

     1 //显示vector <string>类型对象的元素
     2 void DisplayVector(vector <string> stringVector)
     3 {
     4     vector <string> ::iterator iterVector;
     5 
     6     for (iterVector = stringVector.begin();iterVector != stringVector.end();++iterVector)
     7     {
     8         cout<<*iterVector<<"	";
     9     }
    10     cout<<endl;
    11 }
    12 
    13 //变位词的查找
    14 void FindAnagrams()
    15 {
    16     map < string ,vector <string> > signWordMap;  
    17     vector <string> dictVector;
    18     string word;
    19     string sign;
    20     
    21     cout<<"please enter a word ,end with ctrl+z: "<<endl;
    22     while (cin>>word)        //输入字典中单词
    23     {
    24         dictVector.push_back(word);
    25         cout<<"please enter a word ,end with ctrl+z: "<<endl;
    26     }
    27     cout<<"the dictionary is : "<<endl;
    28     DisplayVector(dictVector);
    29 
    30     vector <string> :: iterator iterVector;
    31 
    32     for (iterVector = dictVector.begin();iterVector != dictVector.end();++iterVector)  //制作标识、单词对
    33     {
    34         sign = *iterVector;
    35         sort( sign.begin(),sign.end() );
    36         signWordMap[sign].push_back(*iterVector);
    37     }
    38 
    39     map < string ,vector <string> > :: iterator iterMap;
    40 
    41     for (iterMap = signWordMap.begin();iterMap != signWordMap.end();++iterMap)//输出变位词
    42     {
    43         cout<<"the anagrams signed by "<<(*iterMap).first<<" is :"<<endl;
    44         for (iterVector = (*iterMap).second.begin() ;iterVector != (*iterMap).second.end();++iterVector)
    45         {
    46             cout<<*iterVector<<"	";
    47         }
    48         cout<<endl;
    49     }
    50 }
    51 
    52 int main(void)
    53 {
    54     //test FindAnagrams
    55     FindAnagrams();
    56     return 0;
    57 }

    运行结果:

    please enter a word ,end with ctrl+z:
    tops  stop snap pans top ant at
    please enter a word ,end with ctrl+z:
    please enter a word ,end with ctrl+z:
    please enter a word ,end with ctrl+z:
    please enter a word ,end with ctrl+z:
    please enter a word ,end with ctrl+z:
    please enter a word ,end with ctrl+z:
    please enter a word ,end with ctrl+z:
    ^Z
    the dictionary is :
    tops    stop    snap    pans    top     ant     at
    the anagrams signed by anps is :
    snap    pans
    the anagrams signed by ant is :
    ant
    the anagrams signed by at is :
    at
    the anagrams signed by opst is :
    tops    stop
    the anagrams signed by opt is :
    top
    请按任意键继续. . .
  • 相关阅读:
    hdu 4521 小明系列问题——小明序列(线段树 or DP)
    hdu 1115 Lifting the Stone
    hdu 5476 Explore Track of Point(2015上海网络赛)
    Codeforces 527C Glass Carving
    hdu 4414 Finding crosses
    LA 5135 Mining Your Own Business
    uva 11324 The Largest Clique
    hdu 4288 Coder
    PowerShell随笔3 ---别名
    PowerShell随笔2---初始命令
  • 原文地址:https://www.cnblogs.com/youngforever/p/3185149.html
Copyright © 2011-2022 走看看