几个经典基础算法题目_a 算法题目

练习6,进制的转换:

[cpp]
view plain
copy
print
?

  1. // ConsoleAppHexadecimalTrans.cpp : 定义控制台应用程序的入口点。
  2. //
  3. /*
  4. *问题描述:将十进制转换成二进制或者八进制,16进制
  5. *问题示例:输入50 2,输出110010
  6. *函数功能:
  7. *函数原形:void HexadecimalTrans(int n, int d)
  8. *参数:int n,十进制整数 int d,进制数
  9. *返回值:无
  10. *时间复杂度:
  11. *备注:无
  12. *日期:2014/11/30
  13. *算法描述:
  14. */
  15. #include “stdafx.h”
  16. #include 
  17. using namespace std;
  18. int flag=1;
  19. void HexadecimalTrans(int n, int d)
  20. {
  21. int mod;
  22. mod=n%d;                       //n表示数字,d表示进制
  23. n=n/d;
  24. while(flag && n)               //辗转相除
  25. HexadecimalTrans(n,d);
  26. switch(mod)
  27. {
  28. case 10:
  29. cout<<“A”;
  30. break;
  31. case 11:
  32. cout<<“B”;
  33. break;
  34. case 12:
  35. cout<<“C”;
  36. break;
  37. case 13:
  38. cout<<“D”;
  39. break;
  40. case 14:
  41. cout<<“E”;
  42. break;
  43. case 15:
  44. cout<<“F”;
  45. break;
  46. default:
  47. cout<<mod;    //二进制和八进制均在这里输出,mod保存了辗转相除的每次结果
  48. }
  49. flag=0;
  50. }
  51. int _tmain(int argc, _TCHAR* argv[])
  52. {
  53. int n, d;
  54. cout<<“输入十进制数字:”<<endl;
  55. cin>>n;
  56. cout<<“请输入将要进行的进制转换(2,8,16):”<<endl;
  57. cin>>d;
  58. HexadecimalTrans(n,d);       //调用转换函数
  59. cout<<endl;
  60. system(“pause”);
  61. return 0;
  62. }

练习7,查找指定数据的位置(暴力搜索):

[cpp]
view plain
copy
print
?

  1. // ConsoleAppSpecifiedSearch.cpp : 定义控制台应用程序的入口点。
  2. //
  3. /*
  4. *问题描述:暴力搜索遍历查找,从100个随机函数中(100-999)查找指定数字的位置
  5. *问题示例:
  6. *函数功能:查找指定的数
  7. *函数原形:int FindNum(int num[], int x)
  8. *参数:int num[],要查找的数组, int x,要查找的数
  9. *返回值:数字的位置
  10. *时间复杂度:O()
  11. *备注:无
  12. *日期:2014/7/30
  13. *算法描述:
  14. */
  15. #include “stdafx.h”
  16. #include 
  17. #include <stdlib.h>
  18. #include <time.h>
  19. using namespace std;
  20. #define MAX 100
  21. /*
  22. *函数功能:产生指定的随机数
  23. *函数原形:void RandNumIn(int num[])
  24. *参数:int num[],产生的随机数保存到数组num中
  25. *返回值:无
  26. */
  27. void RandNumIn(int num[])
  28. {
  29. int i;
  30. srand((unsigned)time(NULL));       //得到随机种子
  31. for(i=0; i<MAX; i++)
  32. num[i]=100+rand()%900;             //生成100–999以内的随机三位整数
  33. }
  34. /*
  35. *函数功能:输出产生的随机数
  36. *函数原形:void RandNumOut(int num[])
  37. *参数:int num[],将要输出的数组
  38. *返回值:无
  39. */
  40. void RandNumOut(int num[])
  41. {
  42. int count=0;
  43. for(int i=0; i<MAX; i++)
  44. {
  45. cout<<num[i]<<"  ";
  46. count++;
  47. if(0==count%10)
  48. cout<<endl;
  49. }
  50. }
  51. /*
  52. *函数功能:查找指定的数
  53. *函数原形:int FindNum(int num[], int x)
  54. *参数:int num[],要查找的数组, int x,要查找的数
  55. *返回值:数字的位置
  56. */
  57. int FindNum(int num[], int x)
  58. {
  59. for(int i=0; i<MAX; i++)
  60. if(x == num[i])        //遍历查找指定数字的位置
  61. return i;
  62. return 0;
  63. }
  64. int _tmain(int argc, _TCHAR* argv[])
  65. {
  66. int x, pos, num[MAX];        //设置存储数组
  67. RandNumIn(num);
  68. cout<<"随机生成的数字: "<<endl;
  69. RandNumOut(num);
  70. cout<<“请输入要查找的三位整数”<<endl;
  71. cin>>x;
  72. pos=FindNum(num, x);           //调用查找函数
  73. if(pos)
  74. cout<<“太好了!”<<x<< "的位置在: "<< pos<<endl;
  75. else
  76. cout<<“抱歉!”<<x<< "并未找到! "<<endl;
  77. system(“pause”);
  78. return 0;
  79. }

练习8,二分法查找指定数据位置:

[cpp]
view plain
copy
print
?

  1. // ConsoleAppSpecifiedSearch.cpp : 定义控制台应用程序的入口点。
  2. //
  3. /*
  4. *问题描述:二分法遍历查找,从100个随机函数中(100-999)查找指定数字的位置
  5. *问题示例:
  6. *函数功能:二分查找法查找指定的数
  7. *函数原形:int SpecialFindNum(int num[], int x, int low, int high)
  8. *参数:
  9. int num[],要查找的数组,
  10. int x,要查找的数
  11. int low, 查找的起始位置
  12. int high,查找的末端位置
  13. *返回值:数字的位置
  14. *时间复杂度:O()
  15. *备注:无
  16. *日期:2014/7/30
  17. *算法描述:
  18. */
  19. #include “stdafx.h”
  20. #include 
  21. #include <stdlib.h>
  22. #include <time.h>
  23. using namespace std;
  24. #define MAX 101
  25. /*
  26. *函数功能:产生指定的随机数
  27. *函数原形:void RandNumIn(int num[])
  28. *参数:int num[],产生的随机数保存到数组num中
  29. *返回值:无
  30. */
  31. void RandNumIn(int num[])
  32. {
  33. int i;
  34. srand((unsigned)time(NULL));       //得到随机种子
  35. for(i=1; i<MAX; i++)
  36. num[i]=100+rand()%900;             //生成100–999以内的随机三位整数
  37. }
  38. /*
  39. *函数功能:输出产生的随机数
  40. *函数原形:void RandNumOut(int num[])
  41. *参数:int num[],将要输出的数组
  42. *返回值:无
  43. */
  44. void RandNumOut(int num[])
  45. {
  46. int count=0;
  47. for(int i=1; i<MAX; i++)
  48. {
  49. cout<<num[i]<<"  ";
  50. count++;
  51. if(0==count%10)
  52. cout<<endl;
  53. }
  54. }
  55. /*
  56. *函数功能:快速排序法
  57. *函数原形:void QuickSort(int num[], int low, int high)
  58. *参数:
  59. int num[],要排序的数组,
  60. int low, 查找的起始位置
  61. int high,查找的末端位置
  62. *返回值:无
  63. */
  64. void QuickSort(int num[], int low, int high)
  65. {
  66. int l, h;
  67. if(low<high)
  68. {
  69. l=low;
  70. h=high;
  71. num[0]=num[l];
  72. while(l<h)
  73. {
  74. while(l<h && num[h]>=num[0])
  75. h–;     //利用快速排序是数据有序
  76. num[l]=num[h];
  77. while(l<h && num[l]<=num[0])
  78. l++;
  79. num[h]=num[l];
  80. }
  81. num[l]=num[0];
  82. QuickSort(num, low, l-1);
  83. QuickSort(num, l+1, high);
  84. }
  85. }
  86. /*
  87. *函数功能:二分查找法查找指定的数
  88. *函数原形:int SpecialFindNum(int num[], int x, int low, int high)
  89. *参数:
  90. int num[],要查找的数组,
  91. int x,要查找的数
  92. int low, 查找的起始位置
  93. int high,查找的末端位置
  94. *返回值:数字的位置
  95. */
  96. int SpecialFindNum(int num[], int x, int low, int high)
  97. {
  98. int mid;                 //中间位置
  99. while(low<=high)
  100. {
  101. mid=(low+high)/2; /* 找到 */
  102. if(x==num[mid])
  103. return mid;
  104. else if(x<num[mid])      //两边的游标不停往中间移动比较
  105. high=mid-1;
  106. else
  107. low=mid+1;
  108. }
  109. return 0;
  110. }
  111. int _tmain(int argc, _TCHAR* argv[])
  112. {
  113. int x, pos, num[MAX];
  114. RandNumIn(num);
  115. cout<<“排序前:”<<endl;
  116. RandNumOut(num);
  117. QuickSort(num, 1, MAX-1);
  118. cout<<“排序后:”<<endl;
  119. RandNumOut(num);
  120. cout<<“请输入要查找的数:”<<endl;
  121. cin>>x;
  122. pos=SpecialFindNum(num, x, 1, MAX-1);            //调用查找函数
  123. if(pos)
  124. cout<<“太好了!”<<x<< "的位置在: "<< pos<<endl;
  125. else
  126. cout<<“抱歉”<<x<< "没有找到 "<<endl;
  127. system(“pause”);
  128. return 0;
  129. }

练习9,字符串中指定数据出现次数

[cpp]
view plain
copy
print
?

  1. // ConsoleAppCharCount.cpp : 定义控制台应用程序的入口点。
  2. //
  3. /*
  4. *问题描述:设计一个程序,统计随机给出的字符串的数字的个数,字母的个数,特殊字符的个数
  5. *问题示例:123asd,数字3,字母3,特殊字符0
  6. *函数功能:统计字符串中的数据
  7. *函数原形:void CharCal(char *str, int count[])
  8. *参数:char *str,欲统计的字符串, int count[],用于存储统计结果
  9. *返回值:无
  10. *时间复杂度:O()
  11. *备注:无
  12. *日期:2014/7/30
  13. *算法描述:
  14. */
  15. #include “stdafx.h”
  16. #include 
  17. #include <string.h>
  18. #define MAX 1024
  19. using namespace std;
  20. /*
  21. *函数功能:统计字符串中的数据
  22. *函数原形:void CharCal(char *str, int count[])
  23. *参数:char *str,欲统计的字符串, int count[],用于存储统计结果
  24. *返回值:无
  25. */
  26. void CharCal(char *str, int count[])
  27. {
  28. while(*str)
  29. {
  30. if((*str>=‘0’)&&(*str<=‘9’))      //统计数字型字符
  31. count[0]++;
  32. else if(((*str>=‘a’)&&(*str<=‘z’)) || ((*str>=‘A’)&&(*str<=‘Z’))) //统计字符型字符
  33. count[1]++;
  34. else                      //其他特殊字符
  35. count[2]++;
  36. str++;//指针移动
  37. }
  38. }
  39. /*
  40. *函数功能:输出统计结果
  41. *函数原形:void CharCount( int count[])
  42. *参数: int count[],存储统计结果的数组
  43. *返回值:无
  44. */
  45. void CharCount( int count[])
  46. {
  47. for(int i=0; i<3; i++)
  48. {
  49. switch(i)
  50. {
  51. case 0:
  52. cout<<“数字:”<<count[i]<<endl;
  53. break;
  54. case 1:
  55. cout<<“字符:”<< count[i]<<endl;
  56. break;
  57. case 2:
  58. cout<<“特殊字符:”<<count[i]<<endl;
  59. break;
  60. }
  61. }
  62. }
  63. int _tmain(int argc, _TCHAR* argv[])
  64. {
  65. char str[MAX];                  //定义存储输入字符串的数组
  66. int  count[3];  //用于存储统计结果0->数字; 1->字符; 2->其他
  67. memset(count, 0, 3*sizeof(int));      //初始化统计数组
  68. cout<<"输入字符串: "<<endl;
  69. cin>>str;
  70. CharCal(str, count);//统计
  71. CharCount(count);//输出显示
  72. system(“pause”);
  73. return 0;
  74. }

练习10,逆序输出字符串

[cpp]
view plain
copy
print
?

  1. // ConsoleAppCharTest.cpp : 定义控制台应用程序的入口点。
  2. //
  3. /*
  4. *问题描述:输入字符串,将其逆序输出
  5. *问题示例:输入,asdfgh,输出hgfdsa
  6. *函数功能:逆序输出字符串的内容
  7. *函数原形:void Reverse( char* s, int left, int right );
  8. *参数:
  9. char *,欲逆序的字符串,
  10. int left, 逆序的左起点
  11. int right,逆序的右尾点
  12. *返回值:无
  13. *时间复杂度:O(n)
  14. *备注:无
  15. *日期:2014/7/30
  16. *算法描述:
  17. */
  18. #include “stdafx.h”
  19. #include
  20. using namespace std;
  21. void Reverse( char* s, int left, int right );
  22. int _tmain(int argc, _TCHAR* argv[])
  23. {
  24. int len;
  25. char a[100];
  26. while(1)
  27. {
  28. cout<<“请输入字符串a:”<<endl;
  29. cin>>a;
  30. len=strlen(a);
  31. Reverse(a,0,len-1);
  32. for(int i=0;i<len;i++)
  33. cout<<a[i];
  34. cout<<endl;
  35. }
  36. return 0;
  37. }
  38. //算法一: 对字符串s在指定区间left和right之间进行逆序,递归法
  39. void Reverse( char* s, int left, int right )
  40. {
  41. if(left >= right)
  42. return;
  43. char t = s[left] ;
  44. s[left] = s[right] ;
  45. s[right] = t ;
  46. Reverse(s, left + 1, right - 1) ;
  47. }
  48. /*
  49. //算法二:与上面的方法没有太大区别
  50. void Reverse( char* s, int left, int right )
  51. {
  52. while( left < right )
  53. {
  54. char t = s[left] ;
  55. s[left++] = s[right] ;
  56. s[right–] = t ;
  57. }
  58. }*/

练习11,字符串包含判断

[cpp]
view plain
copy
print
?

  1. // ConsoleAppCharTest.cpp : 定义控制台应用程序的入口点。
  2. //
  3. /*
  4. *问题描述:输入两个字符串,判断相互之间字符串是否包含
  5. *问题示例:输入,asdfgh,输出asd,结果,包含!
  6. *函数功能:判断两个字符串是否包含
  7. *函数原形:bool IsContain(char *pStrA, char *pStrB);
  8. *参数:
  9. char *pStrA, 第一个字符串
  10. char *pStrB,第二个字符串
  11. *返回值:布尔变量
  12. *时间复杂度:O(n)
  13. *备注:无
  14. *日期:2014/7/30
  15. *算法描述:
  16. */
  17. #include “stdafx.h”
  18. #include “iostream”
  19. using namespace std;
  20. bool IsContain(char *pStrA, char *pStrB);
  21. int _tmain(int argc, _TCHAR* argv[])
  22. {
  23. char a[10],b[10];
  24. bool flag;
  25. while(true)
  26. {
  27. cout<<“Please Enter characters A:”<<endl;
  28. cin>>a;
  29. cout<<“Please Enter characters B:”<<endl;
  30. cin>>b;
  31. flag=IsContain(a, b);
  32. if (flag==false)
  33. cout<<“Not Contain!”<<endl;
  34. else
  35. cout<<“Contain!”<<endl;
  36. }
  37. return 0;
  38. }
  39. //算法1
  40. bool IsContain(char *pStrA, char *pStrB)
  41. {
  42. int lenA = strlen(pStrA);
  43. int lenB = strlen(pStrB);
  44. int i,j;
  45. char temp;
  46. for( i = 0; i < lenA; i++)
  47. {//直接对字符数组A进行循环移位再立马进行字符包含判断
  48. temp = pStrA[0];
  49. for( j = 0; j < lenA - 1; j++)
  50. pStrA[ lenA - 1] = pStrA[j + 1];
  51. pStrA[j] = temp;
  52. if(strncmp(pStrA, pStrB, lenB) == 0)
  53. return true;
  54. }
  55. //若果执行到最后都还没有匹配成功,则返回false
  56. if(i == lenA)
  57. return false;
  58. }/*
  59. //算法2
  60. bool IsContain(char *pStrA, char *pStrB)
  61. {
  62. int lenp = strlen(pStrA);
  63. char *temp = (char*)malloc(2 * lenp + 1);//动态分配内存
  64. strcpy_s(temp,2 * lenp + 1,pStrA);
  65. strcpy_s(temp + lenp, 2 * lenp + 1,pStrA);
  66. if(strstr(temp, pStrB))
  67. return TRUE;
  68. else
  69. return FALSE;
  70. }*/

练习12,打印任意位元的格雷码序列:

比如3位的所有格雷码:

000
001
011
010
110
111
101
100

代码如下:

[html]
view plain
copy
print
?
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. // ConsoleAppGrayCode.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include “stdafx.h”
  4. #include “iostream”
  5. using namespace std;
  6. bool GrayCode(int nBits);
  7. int changeBit(int a);
  8. int _tmain(int argc, _TCHAR* argv[])
  9. {
  10. int nBits=0;
  11. cout<<“请输入位元长度:”<<endl;
  12. cin>>nBits;
  13. GrayCode(nBits);
  14. system(“pause”);
  15. return 0;
  16. }
  17. bool GrayCode(int nBits)
  18. {
  19. bool flag=true;
  20. do
  21. {
  22. if (nBits<0)
  23. {
  24. cout<<“你的输入有误,请重新输入:”<<endl;
  25. cin>>nBits;
  26. }else
  27. {
  28. flag=false;
  29. }
  30. } while (flag);
  31. int *pGray=new int[nBits];
  32. for (int i=0;i<nBits;i++)
  33. {
  34. pGray[i]=0;
  35. cout<<0;
  36. }
  37. cout<<endl;
  38. for (int j=1;j<pow(2,nBits);j++)
  39. {
  40. if (j%2==1)
  41. {
  42. pGray[nBits-1]=changeBit(pGray[nBits-1]);
  43. for (int i=0;i<nBits;i++)
  44. {
  45. cout<<pGray[i];
  46. }
  47. cout<<endl;
  48. }else
  49. {
  50. int j=0;
  51. for ( j=nBits-1;j>=0;j–)
  52. {
  53. if (pGray[j]==1)
  54. {
  55. pGray[j-1]=changeBit(pGray[j-1]);
  56. break;
  57. }
  58. }
  59. for (int i=0;i<nBits;i++)
  60. {
  61. cout<<pGray[i];
  62. }
  63. cout<<endl;
  64. }
  65. }
  66. return true;
  67. }
  68. int changeBit(int a)
  69. {
  70. if (a==0)
  71. {
  72. return 1;
  73. }else
  74. {
  75. return 0;
  76. }
  77. }

另一份可参考代码:

[html]
view plain
copy
print
?
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. #include 
  2. using namespace std;
  3. #define CHANGE_BIT(a) a=((a==‘0’)? ‘1’:‘0’)             //定义宏实现改变位元值
  4. #define NEXT_BIT(x) x=(1-(x))                         //设定奇数项或偶数项
  5. /***************构建n位元的格雷码***************/
  6. void findGrayCode(int n){
  7. if (n <=0)
  8. {
  9. cout<<“输入超出有效范围”<<endl;             //验证输入值是否合法
  10. return;
  11. }
  12. char* gray=new char[n];                          //声明存储每个格雷码的数组
  13. for (int i=0;i<n;i++)                               //初始化数组为0
  14. {
  15. gray[i] = ‘0’;
  16. cout<<‘0’;                                  //打印其实格雷码0000…
  17. }
  18. cout<<endl;
  19. int odd = 1;                                     //定义奇数标志,1为奇数项,0为偶数项
  20. int i=0;
  21. /**********************循环构造并输出格雷码*************************/
  22. while(1){
  23. if (odd)                                 //如果为奇数项,更改最右边位元值为相反值
  24. {
  25. CHANGE_BIT(gray[0]);             //本题为反向存储
  26. }else{
  27. /***********************如果为偶数项则查找从数的右边起第一个1的位置*************/
  28. for (i=0;i<n && gray[i]==‘0’;i++);
  29. if (i==n-1)                     //如果i为数的最左边位,则退出循环,所有格雷码查找完成
  30. break;
  31. CHANGE_BIT(gray[i+1]);          //更改第一个1左边的以为的值
  32. }
  33. for (i=n-1;i>=0;i–)                      //输出改格雷码
  34. {
  35. cout<<gray[i];
  36. }
  37. cout<<endl;
  38. NEXT_BIT(odd);                       //更改奇偶属性
  39. }
  40. }
  41. /**************************测试主函数*************************/
  42. int main(){
  43. int n;
  44. cout<<“输入位元数:”<<endl;
  45. cin>>n;
  46. cout<<n<<“位元的格雷码为:”<<endl;
  47. findGrayCode(n);
  48. return 0;
  49. }

练习14,约舍夫出局

N个人围成一圈,从第一个开始报数,第M个将出局,最后剩下一个,其余人都将出局。

例如N=6,M=5,被出局的顺序是:5,4,6,2,3,1。

(1)CircleList.h的代码如下:

[html]
view plain
copy
print
?

  1. #include “stdafx.h”
  2. #include “iostream”
  3. using namespace std;
  4. templateclass LinkList;
  5. template
  6. class LinkNode
  7. {
  8. public:
  9. LinkNode()
  10. {
  11. next = NULL;
  12. data = 0;
  13. }
  14. //函数参数表中的形参允许有默认值,但是带默认值的参数需要放后面
  15. LinkNode(DataType item)
  16. {
  17. next = NULL;
  18. data = item;
  19. }
  20. friend class LinkList;
  21. private:
  22. DataType data;
  23. LinkNode *next;
  24. };
  25. /* 带头结点的单链表定义 */
  26. template
  27. class LinkList
  28. {
  29. public:
  30. //无参数的构造函数
  31. LinkList(int size)
  32. {
  33. head = new LinkNode;//头结点
  34. maxSize=size;
  35. nLength=0;
  36. }
  37. //析构函数
  38. ~LinkList()
  39. {
  40. }
  41. //获取链表长度
  42. int Length() const
  43. {
  44. return nLength;
  45. }
  46. //定位指定的位置,返回该位置上的结点指针
  47. LinkNode* Locate(int pos);
  48. //在指定位置pos插入值为item的结点,失败返回false
  49. bool Insert(DataType item, int pos);
  50. //打印链表
  51. void Print() const;
  52. //创建一个链表环
  53. void CreatCircle();
  54. //判断是否纯在单链表环
  55. bool IsCircle();
  56. //数数移动
  57. bool CountMove( int nStep=0 ,int i=0 );
  58. private:
  59. LinkNode *head;
  60. int maxSize;
  61. int nLength;
  62. };
  63. /* 返回链表中第pos个元素的地址,如果pos<0或pos超出链表最大个数返回NULL */
  64. template
  65. LinkNode* LinkList::Locate(int pos)
  66. {
  67. LinkNode *p = head;//head和p指向共同的内容,头结点无数据,只是个指针
  68. if (pos < 0)
  69. {
  70. cerr<<“位置参数有错误”<<endl;
  71. return NULL;
  72. }
  73. int i = 0;
  74. while (p != NULL && i < pos)
  75. {
  76. p = p->next;
  77. i++;
  78. }
  79. return p;
  80. }
  81. template
  82. bool LinkList::Insert(DataType item, int pos)
  83. {
  84. if (Length() >= maxSize)
  85. {
  86. cout<<“错误:链表已满”<<endl;
  87. exit(1);
  88. }
  89. LinkNode *p = Locate(pos);
  90. LinkNode *newNode = new LinkNode(item);//创建新节点
  91. if (NULL == newNode)
  92. {
  93. cerr << “分配内存失败!” << endl;
  94. exit(1);
  95. }
  96. newNode->next = p->next;
  97. p->next = newNode;
  98. nLength++;
  99. return true;
  100. }
  101. template
  102. void LinkList::Print() const
  103. {
  104. int count = 0;
  105. LinkNode *p = head;
  106. while (NULL != p->next)
  107. {
  108. p = p->next;
  109. std::cout << p->data << " ";
  110. if (++count % 15 == 0)  //每隔十个元素,换行打印
  111. cout << std::endl;
  112. }
  113. }
  114. //创建一个链表环
  115. template
  116. void LinkList:: CreatCircle()
  117. {
  118. int nLen=Length();
  119. int nLen1=1;
  120. LinkNode *ptail=Locate(nLen);
  121. LinkNode *pcirStart=Locate(nLen1);
  122. ptail->next=pcirStart;
  123. }
  124. //是否纯在链表环?
  125. template
  126. bool LinkList::IsCircle()
  127. {
  128. if ( head ==NULL)
  129. {
  130. cerr<<“空链表”<<endl;
  131. exit(1);
  132. }
  133. LinkNode *pFast,*pSlow;
  134. pSlow=head;
  135. pFast=head;
  136. while(pFast!=NULL&&pFast->next!=NULL)
  137. {
  138. pFast=pFast->next->next;
  139. pSlow=pSlow->next;
  140. if (pSlow==pFast)
  141. {
  142. return true;
  143. break;
  144. }
  145. }
  146. return false;
  147. }
  148. template
    
  149. bool LinkList::CountMove( int nStep,int k)//指定出局人数
  150. {
  151. if (  k > Length() )
  152. {
  153. cerr<<“写你麻痹,滚回去检查!”<<endl;
  154. return false;
  155. }
  156. LinkNode *pCurr=NULL,*pPrev=NULL;
  157. int i = 0;    // 计数
  158. int n=0;
  159. pCurr = pPrev = head;
  160. while( n < k )
  161. {
  162. if (i == nStep)
  163. {
  164. // 踢出环
  165. cout<<“第 “<<n+1<<” 次出局”<<":  ";
  166. cout<<“当前出局人编号”<data<<endl;    // 显示出圈循序
  167. pPrev->next = pCurr->next;
  168. delete pCurr;
  169. pCurr = pPrev->next;
  170. i = 1;
  171. n++;
  172. }
  173. pPrev = pCurr;
  174. pCurr = pCurr->next;
  175. if (pPrev == pCurr)
  176. {
  177. // 最后一个
  178. cout<<“第 “<<n+1<<” 次出局”<<":  ";
  179. cout<<“最后的出局人为:”<data<<" ";    // 显示出圈循序
  180. delete pCurr;
  181. //最后一个节点删除后的“擦屁股”处理
  182. pCurr=NULL;
  183. head->next=head;
  184. n++;
  185. break;
  186. }
  187. i++;
  188. }
  189. return true;
  190. }

(2)主测试代码:

[html]
view plain
copy
print
?

  1. // Win32AppCircleOut.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include “stdafx.h”
  4. #include “CircleList.h”
  5. using namespace std;
  6. int _tmain(int argc, _TCHAR* argv[])
  7. {
  8. int nlen=10;
  9. LinkList s(nlen);
  10. for (int i=0;i<nlen;i++)
  11. {
  12. s.Insert(i+1,i);
  13. }
  14. s.CreatCircle();
  15. if (s.IsCircle())
  16. {
  17. cout<<“环已经生成,可以开始了!”<<endl;
  18. }
  19. s.CountMove(3,10);//数到3出局,记录前30个人的出局情况
  20. system(“pause”);
  21. return 0;
  22. }

练习15,汉诺塔递归

汉诺塔递归问题:

[html]
view plain
copy
print
?

  1. // ConsoleAppHanoi.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include “stdafx.h”
  4. #include “iostream”
  5. using namespace std;
  6. int Hanoicount=0;
  7. bool HanoiMove(int n,char a,char b,char c);//将n个盘从a借助b移动到c
  8. int _tmain(int argc, _TCHAR* argv[])
  9. {
  10. HanoiMove(5,‘A’,‘B’,‘C’);
  11. cout<<“共进行了:”<<Hanoicount<<“次”<<endl;
  12. system(“pause”);
  13. return 0;
  14. }
  15. bool HanoiMove(int n,char a,char b,char c)
  16. {
  17. if ( n == 1 )
  18. {
  19. cout<<a<<“-------->”<<c<<endl;
  20. Hanoicount++;
  21. }else
  22. {
  23. HanoiMove(n-1,a,c,b);
  24. cout<<a<<“-------->”<<c<<endl;
  25. HanoiMove(n-1,b,a,c);
  26. Hanoicount++;
  27. }
  28. return true;
  29. }

练习,16****求某年某月某日是当年的第几天

[html]
view plain
copy
print
?

  1. / ConsoleAppRunNian.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include “stdafx.h”
  4. #include “iostream”
  5. #include “windows.h”
  6. using namespace std;
  7. int leap(int a)                                     /*自定义函数leap用来指定年份是否为闰年*/
  8. {
  9. if (a % 4 == 0 && a % 100 != 0 || a % 400 == 0)             /*闰年判定条件*/
  10. return 1;                                   /*是闰年返回1*/
  11. else
  12. return 0;                                   /*不是闰年返回0*/
  13. }
  14. int number(int year, int m, int d) /*自定义函数number计算输入日期为该年第几天*/
  15. {
  16. if ( m>12 || d > 31 || d < 0 || m<0)
  17. {
  18. cerr<<“参数错误!”<<endl;
  19. return -1;
  20. }
  21. if (m ==2)
  22. {
  23. if (d > 29)
  24. {
  25. cerr<<“参数错误!”<<endl;
  26. return -1;
  27. }
  28. }
  29. int sum = 0, i;
  30. /*数组a存放平年每月的天数*/
  31. int a[12] ={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  32. int b[12] ={31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};      /*数组b存放闰年每月的天数*/
  33. if (leap(year) == 1)                                /*判断是否为闰年*/
  34. for (i = 0; i < m - 1; i++)
  35. sum += b[i];                                /*是闰年,累加数组b前m-1个月份天数*/
  36. else
  37. for (i = 0; i < m - 1; i++)
  38. sum += a[i];                                /*不是闰年,累加数组a钱m-1个月份天数*/
  39. sum += d;                                       /*将前面累加的结果加上日期,求出总天数*/
  40. return sum;                                     /*将计算的天数返回*/
  41. }
  42. void main()
  43. {
  44. int year, month, day, n;           /*定义变量为基本整型*/
  45. cout<<“请输入年月日”<<endl;
  46. cin>>year>>month>>day;             /*输入年月日*/
  47. n = number(year, month, day);                           /*调用函数number*/
  48. while (n == -1)
  49. {
  50. cout<<“请重新输入年月日”<<endl;
  51. cin>>year>>month>>day;             /*输入年月日*/
  52. n = number(year, month, day);                           /*调用函数number*/
  53. }
  54. cout<<“第”<<n<<“天”<<endl;
  55. Sleep(5000);
  56. }

练习17,逻辑推理题

婚礼上的谎言

[html]
view plain
copy
print
?

  1. // ConsoleAppHunLi.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include “stdafx.h”
  4. #include “iostream”
  5. #include “windows.h”
  6. using namespace std;
  7. int _tmain(int argc, _TCHAR* argv[])
  8. {
  9. int a, b, c;
  10. for (a = 1; a <= 3; a++)                             /*穷举a的所有可能*/
  11. for (b = 1; b <= 3; b++)                         /*穷举b的所有可能*/
  12. for (c = 1; c <= 3; c++)                     /*穷举c的所有可能*/
  13. if (a != 1 && c != 1 && c != 3 && a != b && a != c && b != c)
  14. /*如果表达式为真,则输出结果,否则继续下次循环*/
  15. {
  16. cout<<char(‘X’ + a - 1)/*转换数据类型*/<<" 将嫁给 A"<<endl;
  17. cout<<char(‘X’ + b - 1)<<" 将嫁给 B"<<endl;
  18. cout<<char(‘X’ + c - 1)<<" 将嫁给 C"<<endl;
  19. }
  20. Sleep(5000);
  21. return 0;
  22. }

练习18,二维数组转换为一维数组:

[html]
view plain
copy
print
?

  1. // ConsoleAppMatTrans.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include “stdafx.h”
  4. #include “iostream”
  5. using namespace std;
  6. /******************
  7. 定义二维数组char array[x][y];
  8. 1.只定义个一维的就可以了
  9. char *array;
  10. array = new char[x*y]; 这种方式等价于char *array = new char[x*y];
  11. 访问的时候*(array+i*y+j)表示array[i][j]
  12. 2.定义一个二维数组
  13. char **array1
  14. array1 = new char *[x];
  15. for(i=0;i<x;++i)
  16. array1[i] = new char[y];
  17. …用的时候可以直接array1[i][j]
  18. 注意delete
  19. *************/
  20. int Trans2DArray(int **src2dArr,int nrow,int ncol,int *dst1dArr);
  21. int _tmain(int argc, _TCHAR* argv[])
  22. {
  23. int** mat;
  24. int row=3,col=3;//row为行数
  25. cout<<“请输入二维数组的行数和列数(空格隔开,比如“3 3”)”<<endl;
  26. cin>>row>>col;
  27. mat =new int*[row];//二维数组的每行的指针
  28. cout<<“请输入二维数组:”<<endl;
  29. for (int i=0;i<row;i++)
  30. {
  31. mat[i] = new int[col];
  32. for (int j=0;j<col;j++)
  33. {
  34. cin>>mat[i][j];
  35. }
  36. }
  37. cout<<“二维数组为:”<<endl;
  38. int count=0;
  39. for (int i=0;i<row;i++)
  40. {
  41. for (int j=0;j<col;j++)
  42. {
  43. cout<<mat[i][j]<<" ";
  44. count++;
  45. }
  46. if ( count%col == 0 )
  47. {
  48. cout<<endl;
  49. }
  50. }
  51. int *arr =new int[row*col];
  52. for (int n=0;n<row*col;n++)
  53. {
  54. arr[n]=0;
  55. }
  56. Trans2DArray(mat,row,col,arr);
  57. cout<<“转换后的一维数组为:”<<endl;
  58. for (int k=0;k < row*col;k++)
  59. {
  60. cout<<arr[k]<<" ";
  61. }
  62. delete[] arr;
  63. system(“pause”);
  64. return 0;
  65. }
  66. int Trans2DArray(int **src2dArr,int nRow,int nCol,int *dst1dArr)
  67. {
  68. if (src2dArr == NULL || nRow < 0 || nCol <0)
  69. {
  70. cerr<<“参数错误”<<endl;
  71. return 0;
  72. }
  73. for (int i=0;i<nRow;i++)
  74. {
  75. for (int j=0;j<nCol;j++)
  76. {
  77. dst1dArr[j+i*nCol]=src2dArr[i][j];//j+i*nCol表示第i行j列的数据
  78. }
  79. }
  80. return 1;
  81. }

练习19,求取一个二进制数的长度

定义:二进制长度就是最高位1的下标值+1(下标从0开始),比如16 = 10000,则长度是5, 2= 0010,长度为2

[cpp]
view plain
copy
print
?

  1. #include “stdafx.h”
  2. #include “iostream”
  3. using namespace std;
  4. int BitLength(unsigned int n);
  5. int _tmain(int argc, _TCHAR* argv[])
  6. {
  7. int count=0,a;
  8. do
  9. {
  10. cout<<“请输入一个整数”<<endl;
  11. cin>>a;
  12. count=BitLength(a);
  13. cout<<“该整数对应二进制数的长度为:”<<count<<endl;
  14. } while (a>0);
  15. return 0;
  16. }
  17. //算法一:易阅读
  18. int BitLength(unsigned int n)
  19. {
  20. int c = 0 ;  //计数
  21. while (n)
  22. {
  23. ++c ;
  24. n >>= 1 ;
  25. }
  26. return c ;
  27. }
  28. //算法二:与上面的解法本质一样
  29. int BitLength(unsigned int n)
  30. {
  31. return n ? BitLength1(n >>=1) + 1 : 0 ;
  32. }
  33. //算法三:以空间换时间(参考网络)
  34. int BitLength(unsigned int n)
  35. {
  36. // pow of 2, 2^0 - 2 ^31
  37. int powof2[32] =
  38. {
  39. 1,           2,           4,           8,         16,          32,
  40. 64,         128,         256,         512,       1024,        2048,
  41. 4096,        8192,       16384,       32768,      65536,      131072,
  42. 262144,      524288,     1048576,     2097152,    4194304,     8388608,
  43. 16777216,    33554432,    67108864,   134217728,  268435456,   536870912,
  44. 1073741824,  2147483648
  45. } ;
  46. int left = 0 ;
  47. int right = 31 ;
  48. while (left <= right)
  49. {
  50. int mid = (left + right) / 2 ;
  51. if (powof2[mid] <= n)
  52. {
  53. if (powof2[mid + 1] > n)
  54. return mid + 1; // got it!
  55. else // powof2[mid] < n, search right part
  56. left = mid + 1 ;
  57. }
  58. else // powof2[mid] > n, search left part
  59. right = mid - 1 ;
  60. }
  61. return -1 ;
  62. }

练习20,求两个正整数的最大公约数

碾转相除法:假设f(a,b)是a,b的最大公约数,则f(b,a%b)=f(a,b),即f(b,a%b)同样也是其最大公约数

[cpp]
view plain
copy
print
?

  1. #include “stdafx.h”
  2. #include
  3. using namespace std;
  4. int GyueNum(int x,int y);
  5. int main()
  6. {
  7. int a,b,result;
  8. cout<<“请输入两个任意的整数”<<endl;
  9. cin>>a>>b;
  10. result=GyueNum(a,b);
  11. cout<<result<<endl;
  12. system(“pause”);
  13. return 0;
  14. }
  15. //算法实现1:
  16. int GyueNum(int x,int y)
  17. {
  18. return (!y)?x:GyueNum(y,x%y);//碾转相除法
  19. }

练习21,栈的顺序输出(STL库实现)

[cpp]
view plain
copy
print
?

  1. // ConsoleAppStackTest1.cpp : 定义控制台应用程序的入口点。
  2. //
  3. /*
  4. *函数功能:以 23 56 11 4 87 98入栈,以11 4 56 98 87 23出栈
  5. *函数原形:无
  6. *参数:无
  7. *返回值:无
  8. *时间复杂度:无
  9. *备注:无
  10. *日期:2014/12/13
  11. *原创:是
  12. *作者:EbowTang
  13. *Email:tangyibiao520@163.com
  14. */
  15. #include “stdafx.h”
  16. #include 
  17. #include 
  18. using namespace std;
  19. int _tmain(int argc, _TCHAR* argv[])
  20. {
  21. //顺序入栈,三个参数
  22. stack sta;
  23. sta.push( 23 );
  24. sta.push( 56 );
  25. sta.push( 11 );
  26. cout << sta.top( )<< " ";//输出顶值11
  27. sta.pop( );//删除元素11
  28. sta.push( 4 );
  29. cout << sta.top( )<< " ";//输出顶值4
  30. sta.pop( );//删除元素4
  31. cout << sta.top( ) << " ";//输出顶值56
  32. sta.pop( );//删除元素56
  33. sta.push( 87 );
  34. sta.push( 98 );
  35. cout << sta.top( ) << " ";//输出顶值98
  36. sta.pop( );//删除元素98
  37. cout << sta.top( ) << " ";//输出顶值87
  38. sta.pop( );//删除元素87
  39. cout << sta.top( ) << " ";//输出顶值23
  40. system( “PAUSE” );
  41. return EXIT_SUCCESS;
  42. }

练习22,括号配对问题

描述

现在,有一行括号序列,请你检查这行括号是否配对。

输入

第一行输入一个数N(0<N<=100),表示有N组测试数据。后面的N行输入多组输入数据,每组输入数据都是一个字符串S(S的长度小于10000,且S不是空串),测试数据组数少于5组。数据保证S中只含有"[“,”]“,”(“,”)"四种字符

输出

每组输入数据的输出占一行,如果该字符串中所含的括号是配对的,则输出Yes,如果不配对则输出No

样例输入

3
[(])
(])
([[]()])

样例输出

No
No
Yes

难度3,第2题

方法:(栈的基本运用)

解题思路依次扫描整个字符串,并使用栈进行模拟。对于输入括号(如果不特殊指出,这里的
括号均指的是含圆括号和中括号)
1,如果为左型的括号(比如 “[”   “(”)则入栈
2,如果为右型括号且栈为空或栈顶元素与之不配对则输出No,反之弹出栈顶元素
3,重复1和2步骤直到扫描结束,最后检查栈是否为空,若为空输出Yes反之输出No。

“括号配对”代码实现如下:

[html]
view plain
copy
print
?

  1. #include “iostream”
  2. #include “string”
  3. #include “stack”
  4. using namespace std;
  5. bool BracketMatch(const string srcStr);
  6. int _tmain(int argc, _TCHAR* argv[])
  7. {
  8. system(“color 0A”);
  9. int N = 0;
  10. //申请内存
  11. string src;
  12. while (cin>>N)
  13. {
  14. for (size_t i = 0; i < N; i++)
  15. {
  16. cin >> src;
  17. if (BracketMatch(src))
  18. cout << “YES” << endl;
  19. else
  20. cout << “NO” << endl;
  21. }
  22. }
  23. return 0;
  24. }
  25. bool BracketMatch(const string srcStr)
  26. {
  27. stack s;
  28. //例子[];
  29. if (srcStr[0] == ‘)’ || srcStr[0] == ‘]’)//如果第一个字符就是右括号,则直接pass掉
  30. return false;
  31. for (unsigned int i = 0; i < srcStr.length(); i++)//从左往右开始遍历
  32. {
  33. switch (srcStr[i])
  34. {
  35. //对左括号仅作压栈处理,同时值得注意的是栈中只有左括号
  36. case ‘[’:
  37. s.push(srcStr[i]);
  38. break;
  39. case ‘(’:
  40. s.push(srcStr[i]);
  41. break;
  42. //对于右括号总是判断他是否与栈顶元素配对,否则即可判断不配对
  43. case ‘]’:
  44. if (s.top() == ‘[’)
  45. s.pop();
  46. break;
  47. case ‘)’:
  48. if (s.top() == ‘(’)
  49. s.pop();
  50. break;
  51. default:
  52. cerr << “错误的括号” << endl;
  53. exit(1);
  54. }
  55. }
  56. //判断栈中的情况
  57. if (s.empty())
  58. return true;
  59. else//如果栈中有数据则说明存在不匹配
  60. return false;
  61. }

练习23,奇偶数分离

描述

有一个整型偶数n(2<= n <=10000),你要做的是:先把1到n中的所有奇数从小到大输出,再把所有的偶数从小到大输出。

输入

第一行有一个整数i(2<=i<30)表示有 i 组测试数据;

每组有一个整型偶数n。

输出

第一行输出所有的奇数

第二行输出所有的偶数

样例输入

2
10
14

样例输出

1 3 5 7 9 
2 4 6 8 10 

1 3 5 7 9 11 13 
2 4 6 8 10 12 14 

难度1,第11题

方法:

直接破题,即直接根据题意输出指定内容

“奇偶数分离”代码实现如下:

[html]
view plain
copy
print
?

  1. // ConsoleAppAcmTest11.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include “stdafx.h”
  4. #include “iostream”
  5. using namespace std;
  6. void OddEvenSepar(int *num, int N)
  7. {
  8. for (int i = 0; i < N;i++)
  9. {
  10. int k = 1;
  11. while (k < num[i])
  12. {
  13. if (k % 2 == 1)
  14. {
  15. cout << k << "  ";
  16. }
  17. k++;
  18. }
  19. cout << endl;
  20. int kk = 1;
  21. while (kk < num[i])
  22. {
  23. if (kk % 2 == 0)
  24. {
  25. cout << kk << "  ";
  26. }
  27. kk++;
  28. }
  29. cout << endl;
  30. }
  31. }
  32. int _tmain(int argc, _TCHAR* argv[])
  33. {
  34. system(“color 0A”);
  35. int N = 0;
  36. cout << “请输入测试组数:” << endl;
  37. cin >> N;
  38. int *num = new int[N];
  39. cout << “请输入对应个数的偶数” << endl;
  40. for (int i = 0; i < N;i++)
  41. {
  42. cin>>num[i];
  43. }
  44. cout << endl;
  45. OddEvenSepar(num, N);
  46. delete[] num;
  47. num = NULL;
  48. system(“pause”);
  49. return 0;
  50. }

练习24,五个数求最值

描述

设计一个从5个整数中取最小数和最大数的程序

输入

输入只有一组测试数据,为五个不大于1万的正整数

输出

输出两个数,第一个为这五个数中的最小值,第二个为这五个数中的最大值,两个数字以空格格开。

样例输入

1 2 3 4 5

样例输出

1 5

难度:1,第31题

方法:

排序法,或者直接求取

“五个数求最值”代码实现如下:

[html]
view plain
copy
print
?

  1. // ConsoleAppAcmTest31.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include “stdafx.h”
  4. #include “iostream”
  5. using namespace std;
  6. void getMinMax(int *num,int n)
  7. {
  8. int min = num[0], max = num[0];
  9. for (int j = 0; j < n;j++)
  10. {
  11. if (min>num[j])
  12. {
  13. min = num[j];
  14. }
  15. if (max < num[j])
  16. {
  17. max = num[j];
  18. }
  19. }
  20. cout << “最小值为:” << min << endl;
  21. cout << “最大值为:” << max << endl;
  22. }
  23. int _tmain(int argc, _TCHAR* argv[])
  24. {
  25. system(“color 0A”);
  26. int num[5] = {0};
  27. for (int i = 0; i < 5;i++)
  28. {
  29. cin >> num[i];
  30. }
  31. getMinMax(num,5);
  32. system(“pause”);
  33. return 0;
  34. }

练习25,韩信点兵

描述

相传韩信才智过人,从不直接清点自己军队的人数,只要让士兵先后以三人一排、五人一排、七人一排地变换队形,而他每次只掠一眼队伍的排尾就知道总人数了。输入3个非负整数a,b,c ,表示每种队形排尾的人数(a<3,b<5,c<7),输出总人数的最小值(或报告无解)。已知总人数不小于10,不超过100 。

输入

输入3个非负整数a,b,c ,表示每种队形排尾的人数(a<3,b<5,c<7)。例如,输入:2 4 5

输出

输出总人数的最小值(或报告无解,即输出No answer)。实例,输出:89

样例输入

2 1 6

样例输出

41

难度1,第34题

方法:

暴力破解,遍历出答案

[html]
view plain
copy
print
?

  1. // ConsoleAppAcmTest34.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include “stdafx.h”
  4. #include “iostream”
  5. using namespace std;
  6. int HanXinCount(int *num);
  7. int _tmain(int argc, _TCHAR* argv[])
  8. {
  9. system(“color 0A”);
  10. int *num = new int[3];
  11. cout << “请输入3种排列方式的队尾人数:”<<endl;
  12. for (int i = 0; i < 3;i++)
  13. {
  14. cin >> num[i];
  15. }
  16. int persons = HanXinCount(num);
  17. if (persons==-1)
  18. {
  19. cout << “No Answer” << endl;
  20. }
  21. else
  22. {
  23. cout << “人数共为:” << persons << endl;
  24. }
  25. delete[] num;
  26. num = NULL;
  27. system(“pause”);
  28. return 0;
  29. }
  30. int HanXinCount(int *num)
  31. {
  32. int persons = -1;
  33. for (int i = 10; i <= 100;i++)
  34. {
  35. if ( i%3num[0] && i%5num[1] && i%7==num[2])
  36. {
  37. persons = i;
  38. }
  39. }
  40. return persons;
  41. }

练习26,组合数

描述

找出从自然数1、2、… 、n(0<n<10)中任取r(0<r<=n)个数的所有组合。

输入

输入n、r。

输出

按特定顺序输出所有组合。

特定顺序:每一个组合中的值从大到小排列,组合之间按逆字典序排列。

样例输入

5 3

样例输出

543
542
541
532
531
521
432
431
421
321

难度3,第32题

方法:

DFS法,深度遍历型程序设计

“组合数”代码实现如下:

[html]
view plain
copy
print
?

  1. // ConsoleAppAcmTest32.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include “stdafx.h”
  4. #include “iostream”
  5. using namespace std;
  6. int a[11];
  7. bool visit[11];//存放数据被访问否
  8. void DFSCombiNum1(int n,int cur, int r);
  9. void printNum(int *w, int r);
  10. int _tmain(int argc, _TCHAR* argv[])
  11. {
  12. system(“color 0A”);
  13. int n = 5;
  14. int r = 3;
  15. cout << “确定范围1到n:请输入n的具体值”<<endl;
  16. cin >> n;
  17. while (n>10)
  18. {
  19. cout << “重新确定范围1到n:请输入n的具体值” << endl;
  20. cin >> n;
  21. }
  22. cout << “从1到n取r个数:请输入r的具体值” << endl;
  23. cin >> r;
  24. while (r > n)
  25. {
  26. cout << “重新输入r” << endl;
  27. cin >> r;
  28. }
  29. memset(visit, false, sizeof(visit));//初始化
  30. DFSCombiNum1(n,1, r);
  31. system(“pause”);
  32. return 0;
  33. }
  34. //递归法DFS
  35. void DFSCombiNum1(int n, int cur, int r) //入口、当前层、总层数
  36. {
  37. if (cur > r) //结束条件
  38. return;
  39. for (int i = n; i >= 1; i–)//从n遍历到1,
  40. {
  41. if (!visit[i])//当前这个数没有被访问过,则访问他
  42. {
  43. visit[i] = true;
  44. a[cur] = i;//记录要输出的数字
  45. if (cur == r)//每次当cur增加到r时就输出放在a中的数
  46. {
  47. printNum(a, r);
  48. }
  49. DFSCombiNum1(i - 1, cur + 1, r);
  50. visit[i] = false;
  51. }
  52. }
  53. }
  54. void printNum(int *a, int r)
  55. {
  56. for (int i = 1; i <= r; i++)
  57. {
  58. cout << a[i];
  59. }
  60. cout << endl;
  61. }

练习27,计算超大数相乘:

编写两个超大数相乘,不用考虑负数

[html]
view plain
copy
print
?

  1. #include 
  2. #include 
  3. using namespace std;
  4. void Multiply(const string &a, const string &b, vector &ansStr);
  5. int main()
  6. {
  7. string bigNum1, bigNum2;     // 初始状态用string来存储大数
  8. while (cin >> bigNum1 >> bigNum2)
  9. {
  10. vector ans(bigNum1.size() + bigNum2.size(), 0);//接收答案,这里必须给予ans大小,否则传递参数时out of range
  11. Multiply(bigNum1, bigNum2, ans);
  12. for (unsigned int i = 1; i < ans.size(); i++)
  13. cout << ans[i];
  14. cout << endl;
  15. ans.clear();
  16. }
  17. return 0;
  18. }
  19. void Multiply(const string &a, const string &b, vector &ans)
  20. {
  21. int lena = a.length(),lenb = b.length();
  22. for (int i = 0; i < lena; i++)
  23. {
  24. for (int j = 0; j < lenb; j++)
  25. {//25,a[0]=2,a[1]=5,31,b[0]=3,b[1]=1;推出==》ans[1]=6,ans[2]=17,ans[3]=5,(ans[0]=0)
  26. ans[i + j + 1] += (a[i] - ‘0’)*(b[j] - ‘0’);
  27. }}
  28. for (int i = lena + lenb - 1; i >= 0; i–)// 这里实现进位操作
  29. {
  30. if (ans[i] >= 10)
  31. {
  32. ans[i - 1] += ans[i] / 10;//让高位获得来自低位的进位值,注意ans[i]相对ans[i-1]是低位
  33. ans[i] %= 10;//低位自裁,只保留当前数的个位即可,比如223,只保留3,22给高位
  34. }}}

练习28,单词的部分逆置

举例;“I am  Chinese.”

逆置后为”Chinese. am I“

参考代码:

[html]
view plain
copy
print
?

  1. #include “string”
  2. #include “vector”
  3. #include 
  4. using namespace std;
  5. int main()
  6. {
  7. string str;
  8. while (getline(cin,str))
  9. {
  10. //以此为例 “I am Chinese.”
  11. int i = 0, j = str.size() - 1;
  12. char temp;
  13. //逆置字符串,“esenihC. ma I”
  14. while (j > i)
  15. {
  16. temp = str[i];
  17. str[i] = str[j];
  18. str[j] = temp;
  19. i++; j–;
  20. }
  21. //部分反转,“Chinese. am I”
  22. int begin = 0, end = 0;
  23. int ii = 0;
  24. while (ii < str.size())
  25. {
  26. if (str[ii] != ’ ')//寻找空格前的子串
  27. {
  28. begin = ii;
  29. while (str[ii] != ’ '&& ii < str.size())//这里考虑了在计数最后一个字符时的情况
  30. {
  31. ii++;
  32. }
  33. ii–;
  34. end = ii;
  35. }
  36. while (end > begin)
  37. {
  38. temp = str[begin];
  39. str[begin++] = str[end];
  40. str[end–] = temp;
  41. }
  42. ii++;
  43. }
  44. cout << str << endl;
  45. }
  46. return 0;
  47. }

练习29,二分查找法存在的问题

PS:有的东西表面看上去公正、全面,实际可能走向极端的分立思维,许多客观事物不能简单均分,可能其内在具有复杂的联系,一旦坚持平分,结果倒失去了客观、全面的基础。

时间复杂度

折半搜索每次把搜索区域减少一半,时间复杂度为[外链图片转存中…(img-KufivAW8-1731010094282)]。(n代表集合中元素的个数)

空间复杂度

[外链图片转存中…(img-9WGVdXbi-1731010094282)]。虽以递归形式定义,但是尾递归,可改写为循环

维基百科告诉我们要这样写:为什么呢?

[cpp] 
view plain
copy
print
?

  1. //递归版本
  2. int binary_search( const int arr[], int low, int high, int key)
  3. {
  4. int mid = low+(high-low)/2; // 别用 (low+high)/2 ,因为可能引起溢出问题。
  5. if(low>high)
  6. return -1;
  7. else
  8. {
  9. if(arr[mid]==key)
  10. return mid;
  11. else if(arr[mid]>key)
  12. return binary_search(arr,low,mid-1,key);
  13. else
  14. return binary_search(arr,mid+1,high,key);
  15. }
  16. }

开始分析

一般二分法这样写:

[cpp] 
view plain
copy
print
?

  1. int binarySearch(int arr[], int l, int h, int key)
  2. {
  3. while (l <= h)
  4. {
  5. // find index of middle element
  6. int m = (l+h)/2;
  7. // Check if key is present at mid
  8. if (arr[m] == key) return m;
  9. // If key greater, ignore left half
  10. if (arr[m] < key) l = m + 1;
  11. // If key is smaller, ignore right half
  12. else h = m - 1;
  13. }
  14. // if we reach here, then element was not present
  15. return -1;
  16. }

以上看起来没事,除了一个很微妙的东西,表达“m =(l+r)/ 2″。它不能用于l和r特别大的时候,如果l和r的总和大于最大正int值(2的31次方–1)。将溢出为负值,即求和之后成了负值时,再除以2也是负值。这将导致索引超出范围和不可预知的结果。

所以解决这个问题的方法就是:

mid = ((unsigned int)low + (unsigned int)high)) >> 1 ;

或者

mid = low+(high-low)/2;

练习30,显式的调用析构器和构造器

构造函数是一个很特殊的成员函数,当一个对象被创建时他将会自动被调用。析构器也是一个很特殊的成员函数,当对象在作用域结束时会被自动的隐式调用。当动态分配内存和销毁时也会调用这两个特殊的函数,即new和delete操作符!

进入正题,显式调用这两个特殊的函数:

[cpp] 
view plain
copy
print
?

  1. #include 
  2. using namespace std;
  3. class Test
  4. {
  5. public:
  6. Test()  { cout << “Constructor is executed\n”; }
  7. ~Test() { cout << “Destructor is executed\n”;  }
  8. };
  9. int main()
  10. {
  11. Test();  // 显式调用构造器
  12. Test t; // 创建本地对象
  13. t.~Test(); // 显式调用析构器
  14. return 0;
  15. }
  16. ///输出:
  17. Constructor is executed   (Test()显式调用产生的,同时会产生一个临时对象,并立刻销毁)
  18. Destructor is executed    (临时对象造成的,此时析构器被调用)
  19. Constructor is executed   (创建本地对象产生的)
  20. Destructor is executed    (显式调用析构器产生的,但是并不意味着对象被销毁)
  21. Destructor is executed    (main结束时,析构函数在对象t作用域的末尾调用,起到释放资源的作用)

当构造器被显式调用时,编译器立刻创建了一个未命名的临时对象,同时它也被立刻销毁,这也是为什么输出中的第二行会是“析构器被执行”特别注意,如果对象时动态分配的内存,千万别显式调用析构器,因为delete会调用析构器。

类的成员函数也能调用析构器和构造器

[cpp] 
view plain
copy
print
?

  1. #include 
  2. using namespace std;
  3. class Test
  4. {
  5. public:
  6. Test()  { cout << “Constructor is executed\n”; }
  7. ~Test() { cout << “Destructor is executed\n”;  }
  8. void show()  {  Test();  this->Test::~Test();  }
  9. };
  10. int main()
  11. {
  12. Test t;
  13. t.show();
  14. return 0;
  15. }
  16. 输出:
  17. Constructor is executed
  18. Constructor is executed
  19. Destructor is executed
  20. Destructor is executed
    l <= h)
  21. {
  22. // find index of middle element
  23. int m = (l+h)/2;
  24. // Check if key is present at mid
  25. if (arr[m] == key) return m;
  26. // If key greater, ignore left half
  27. if (arr[m] < key) l = m + 1;
  28. // If key is smaller, ignore right half
  29. else h = m - 1;
  30. }
  31. // if we reach here, then element was not present
  32. return -1;
  33. }

以上看起来没事,除了一个很微妙的东西,表达“m =(l+r)/ 2″。它不能用于l和r特别大的时候,如果l和r的总和大于最大正int值(2的31次方–1)。将溢出为负值,即求和之后成了负值时,再除以2也是负值。这将导致索引超出范围和不可预知的结果。

所以解决这个问题的方法就是:

mid = ((unsigned int)low + (unsigned int)high)) >> 1 ;

或者

mid = low+(high-low)/2;

练习30,显式的调用析构器和构造器

构造函数是一个很特殊的成员函数,当一个对象被创建时他将会自动被调用。析构器也是一个很特殊的成员函数,当对象在作用域结束时会被自动的隐式调用。当动态分配内存和销毁时也会调用这两个特殊的函数,即new和delete操作符!

进入正题,显式调用这两个特殊的函数:

[cpp] 
view plain
copy
print
?

  1. #include 
  2. using namespace std;
  3. class Test
  4. {
  5. public:
  6. Test()  { cout << “Constructor is executed\n”; }
  7. ~Test() { cout << “Destructor is executed\n”;  }
  8. };
  9. int main()
  10. {
  11. Test();  // 显式调用构造器
  12. Test t; // 创建本地对象
  13. t.~Test(); // 显式调用析构器
  14. return 0;
  15. }
  16. ///输出:
  17. Constructor is executed   (Test()显式调用产生的,同时会产生一个临时对象,并立刻销毁)
  18. Destructor is executed    (临时对象造成的,此时析构器被调用)
  19. Constructor is executed   (创建本地对象产生的)
  20. Destructor is executed    (显式调用析构器产生的,但是并不意味着对象被销毁)
  21. Destructor is executed    (main结束时,析构函数在对象t作用域的末尾调用,起到释放资源的作用)

当构造器被显式调用时,编译器立刻创建了一个未命名的临时对象,同时它也被立刻销毁,这也是为什么输出中的第二行会是“析构器被执行”特别注意,如果对象时动态分配的内存,千万别显式调用析构器,因为delete会调用析构器。

类的成员函数也能调用析构器和构造器

[cpp] 
view plain
copy
print
?

  1. #include 
  2. using namespace std;
  3. class Test
  4. {
  5. public:
  6. Test()  { cout << “Constructor is executed\n”; }
  7. ~Test() { cout << “Destructor is executed\n”;  }
  8. void show()  {  Test();  this->Test::~Test();  }
  9. };
  10. int main()
  11. {
  12. Test t;
  13. t.show();
  14. return 0;
  15. }
  16. 输出:
  17. Constructor is executed
  18. Constructor is executed
  19. Destructor is executed
  20. Destructor is executed
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值