简介:40个问题,有难有易,均使用递归完成,需要C/C++的指针、字符串、数组、链表等基础知识作为基础。
1、数字出现的次数
由键盘录入一个正整数,求该整数中每个数字出现的次数。
输入:19931003
输出:
0 2
1 2
3 2
9 2
#include<iostream>
#include<cstring>
using namespace std;void shine(long long number)
{static char array[10]={0};if(number==0){for(int i=0;i<10;i++){if(array[i]==0){continue;}cout<<i<<"\t"<<(int)array[i]<<endl;}memset(array,0,10*sizeof(char));return;}array[number%10]++;shine(number/10);
}int main()
{long long x;while(true){cin>>x;if(x==-1){break;}shine(x);}return 0;
}
2、翻转整数
由键盘输入一个整数(或正或负),翻转该整数,将其输出。
输入:5201319
输出:9131025
输入:-1314025
输出:-5204131
#include<iostream>
using namespace std;long long reverseNumber0(long long number)//number为正整数
{static long long result=0;if(number<=9){number=result*10+number;result=0;//千万不能忽略这一步return number;}result=result*10+number%10;return reverseNumber0(number/10);
}long long reverseNumber(long long number)
{return number>0?reverseNumber0(number):-reverseNumber0(-number);//number翻转后的数字的正负,单独处理
}int main()
{long long x;cin>>x;cout<<reverseNumber(x);return 0;
}
3、偶数数字
由键盘输入一个整数n(n>0 and n<1000000),求该整数n中有多少个偶数数字。
输入:131952025
输出:3
#include<iostream>
using namespace std;int total(long long number)
{if(number<=9){return number%2==0?1:0;}return (number%10%2==0?1:0)+total(number/10);
}int main()
{long long number;cin>>number;cout<<total(number);
}
4、奇数之和
由键盘输入一个整数n(n>0 and n<1000000),求整数n中出现的奇数之和。
如:
n=1003,n中出现的奇数有1、3,那么所求的奇数之和为4。
n=1949,n中出现的奇数有1、9,那么所求的奇数之和为19。
#include<iostream>
using namespace std;int summate(int x)
{if(x<=9){return x%2?x:0;}int temporary=x%10;return (temporary%2?temporary:0)+summate(x/10);
}int main()
{int x;cin>>x;cout<<summate(x)<<endl;return 0;
}
5、5+55+555+5555+55555+555555…(x=5,n=6)
输入正整数x、n,其中x表示其中的数字(x<=9),n表示数字所达到的最高位数(n<10),输出结果。
输入:
5
6
输出:
617280
输入:
9
9
输出:
1111111101
#include<iostream>
using namespace std;
long long shine(int x,int n)
{if(n==1){return x;}return x+shine(x*10+x%10,n-1);
}int main()
{int x,n;cin>>x>>n;cout<<shine(x,n);return 0;
}
6、反向输出
输入整数n(n>0),之后输入n个正整数,按照n个正整数的输入顺序反向输出一次。
输入:
6
13 19 9 26 10 3
输出:
3 10 26 9 19 13
数组版
#include<iostream>
using namespace std;void input(int * array,int length)//倒着存进数组
{if(length==0){return;}input(array+1,length-1);cin>>*array;
}void traverse(int * array,int length)//遍历数组
{if(length==1){cout<<*array<<endl;return;}cout<<*array<<" ";traverse(array+1,length-1);
}int main()
{int length;cin>>length;int array[length];input(array,length);traverse(array,length);return 0;
}
单链表版
#include<iostream>
using namespace std;typedef struct node
{int data;struct node * next;
}Node;Node * input(int x);//录入x个数据,存储在带表头单链表中,返回表头结点
void traverseBack(Node * head);//倒序遍历单链表
void destroy(Node * head);//销毁单链表int main()
{int x;cin>>x;Node * head=input(x);traverseBack(head);destroy(head);return 0;
}
Node * input(int x)
{if(x==0){Node * head=new Node;//创建表头结点head->next=NULL;head->data=-1;//表头结点的数据标记return head;}Node * predecessor=new Node;predecessor->next=NULL;cin>>predecessor->data;
//-----------------------------------------------Node * head=input(x-1);predecessor->next=head->next;head->next=predecessor;
//-----------------------------------------------头插法return head;
}void traverseBack(Node * head)
{if(head->next==NULL)//到达尾结点 递归结束{return;}traverseBack(head->next);if(head->data!=-1)//非表头结点{cout<<head->next->data<<" ";}else//表头结点{cout<<head->next->data<<endl;}
}void destroy(Node * head)
{if(head==NULL){return;}Node * successor=head->next;//存储当前结点的后继结点指针delete head;//销毁当前结点destroy(successor);//将后续结点指针传递到下一层进行处理
}
7、1的个数
输入正整数n(n>1),求出n对应的二进制数字x中1的个数。
如:
n=100,x= 110 0100,x中1的个数为3
n=9999,x= 10 0111 0000 1111, x中0的个数为8
输入:100
输出:3
#include<iostream>
#include<cstring>
using namespace std;long convert(long number)
{if(number==0){return 0;}return number%2+convert(number/2);
}int main()
{long number;while(true){cin>>number;if(number<1){break;}cout<<convert(number)<<endl;}return 0;
}
8、0的个数
输入正整数n(n>1),求出n对应的二进制数字x中0的个数。
如:
n=150,x= 10010110,x中0的个数为4
n=9999,x= 10 0111 0000 1111, x中0的个数为6
输入:150
输出:4
输入:9999
输出:6
#include<iostream>
#include<cstring>
using namespace std;long convert(long number)
{if(number==1){return 0;}return (number%2==0?1:0)+convert(number/2);
}int main()
{long number;while(true){cin>>number;if(number<1){break;}cout<<convert(number)<<endl;}return 0;
}
9、十进制转二进制
输入正整数n(n>1 and n<100000),求出n对应的二进制数字。
输入:6
输出:110
直接输出版
#include<iostream>using namespace std;void toBinary(long x)
{if(x==0)//递归最后一层{return;}int temporary=x%2;//前进时存储x除以2取余的值toBinary(x/2);cout<<temporary;//回归时输出x除以2取余的值
}int main()
{int n;cin>>n;toBinary(n);//函数中缺少换行cout<<endl;//在此加上return 0;
}
数组版
#include<iostream>
#include<cstring>
using namespace std;char * transform(long long x)
{static int length=0;//十进制数转换成二进制数后的长度、也是递归的层数(从1开始)static int index=0;//在函数回归时,数组所使用的下标length++;if(x==0)//到达递归的最后一层{char * result=new char[length];//数组的长度刚刚好的样子,没有浪费result[length-1]='\0';
//-------------------------------------------------------两者在递归最后一层必须归零length=0;index=0;
//-------------------------------------------------------return result;}char * result=transform(x/2);result[index++]=x%2+'0';//将长整型数据变成字符型数据存入数组return result;
}void traverse(char * source)//遍历字符串
{if(*source==0){cout<<endl;return;}cout<<*source;traverse(source+1);
}int main()
{long long x;while(true){cin>>x;if(x<1 || x>100000){cout<<"invalid value"<<endl;break;}traverse(transform(x));}return 0;
}
单链表版
#include<iostream>
using namespace std;struct Node
{char data;Node * next;Node(char data,Node * next):data(data),next(next){}
};Node * toBinary(long x)//把正整数x转换为二进制数之后,存储在单链表中,返回表头结点指针
{if(x==0){Node * head=new Node(-1,nullptr);//创建表头结点,为区别出表头结点,将表头结点的值置为-1return head;//返回表头结点指针 }int temporary=x%2;//将x除以2取余的值临时存储在变量temporary中Node * head=toBinary(x/2);
//---------------------------------------------单链表头插法Node * p=new Node(temporary+'0',nullptr);p->next=head->next;head->next=p;
//---------------------------------------------单链表头插法 return head;
}void traverse(Node * head)//反向遍历带表头单链表
{if(head->next==nullptr)//到达尾结点,即递归的最后一层{return;}traverse(head->next);cout<<head->next->data;if(head->data==-1)//到达表头结点{cout<<endl;}
}int main()
{long x;while(true){cin>>x;if(x<1 || x>100000){cout<<"invalid value"<<endl;break;}traverse(toBinary(x));}return 0;
}
10、最长的连续1
输入正整数n(n>1 and n<100000),求出n对应的二进制数字x中连续1的最大长度。
如:
n=1949,x=111 1001 1101,x中连续的1有三组,第一组是111 1,第二组是111, 第三组是1,最长是的1111,长度为4。
n=500,x=111110100,x中连续的1有两组,第一组是11111,第二组是1, 最长是的11111,长度为5。
n= 888,x= 11 0111 1000,x中的连续1有两组,第一组是11,第二组是1111,最长是的1111,长度为4。
n= 1918,x= 111 0111 1110,x中的连续1有两组,第一组是111,第二组是111111,最长是的111111,长度为6。
输入:1993
输出:5
简易版
#include<iostream>
using namespace std;int getLength(long number)
{static int length=0;//存储每组连续1的长度static int lengthMaximum=-1;//存储连续1的最大长度if(number==0){//递归的最后一层number=lengthMaximum>length?lengthMaximum:length;
//--------------------------------------------------------------变量值需及时还原length=0;lengthMaximum=-1;
//--------------------------------------------------------------变量值需及时还原return number;}if(number%2==1)//number除以2取余为1,length就进行累加{length++;}else//一旦number除以2取余为0且length>0,说明一组连续1的length累加结束{if(length>0){lengthMaximum=lengthMaximum<length?length:lengthMaximum;length=0;}}return getLength(number/2);
}int main()
{long x;while(true){cin>>x;if(!(x>1 && x<100000)){break;}cout<<getLength(x)<<endl;}return 0;
}
困难版
#include <iostream>using namespace std;int longestContinuousOne(int number);//求整数n的二进制表示中,连续1的最大长度int main()
{long x;while(true){cin>>x;if(!(x>1 && x<100000)){break;}cout<<longestContinuousOne(x)<<endl;}return 0;
}int longestContinuousOne(int number)
{static int counter=0;//计算连续1长度的变量if(number==0)//到达递归边界,开始回归{number=counter;counter=0;/*某段连续1的长度,在number%2为1时,长度counter自增,在number%2为0时,将counter的值存储在temporary中,counter置为0,等待下一段连续1的长度统计最后一段连续1的长度,不会经过number%2为0这个条件的判断,所以在递归边界处将counter的值存储在number中,返回number*/return number;}if(number%2==1)//整数n对2取余为1,则counter自增{counter++;}else//整数n对2取余为0{if(counter>0)//且counter大于0,某一段连续1的长度已经统计完毕{int temporary=counter;//存储counter的值counter=0;//将counter置为0,待统计下一段连续1的长度int length=longestContinuousOne(number/2);//递归调用,返回长度较大的一段连续1的长度return length>temporary?length:temporary;//将返回的length与temporary比较,返回较大的那个值}}return longestContinuousOne(number/2);
}
11、变成数组
输入正整数n(n>10 and n<987654321),将n的每位数字从高位到低存储到数组,再遍历数组,数组元素之间用逗号隔开。
输入:13192520
输出:1,3,1,9,2,5,2,0
#include<iostream>
using namespace std;char * transform(long long number)//正整数的数字们转变成数组元素,返回数组首字节指针
{static int length=0;//既计算number的长度,也作数组的下标static char * begin=nullptr;//存储数组首字节指针length++;if(number==0){//到达递归的最后一层char * array=new char[length];//确定number的长度length后创建数组array[length-1]='\0';//length比number的实际长度要大1是为了存储'\0'begin=array;//存储数组首字节指针length=0;return array;}char temporary=number%10+'0';//整型数据转成字符型数据char * array=transform(number/10);*begin++=temporary;return array;
}void traverse(char * source)//遍历字符数组
{if(*(source+1)==0){cout<<*source<<endl;return;}cout<<*source<<",";traverse(source+1);
}int main()
{long long number;while(true){cin>>number;if(number<10 || number>987654321){break;}traverse(transform(number));}return 0;
}
12、变成单链表
输入正整数n(n>10 and n<987654321),将n的每位数字存储到单链表中,再遍历单链表,结点之间用箭头"->"隔开。
输入:13192520
输出:1->3->1->9->2->5->2->0
#include<iostream>using namespace std;struct Node
{short data;Node * next;Node(short data,Node * next):data(data),next(next){}
};Node * transform(long long x)
{if(x==0){Node * head=new Node(-1,nullptr);//表头结点的值置为-1,是为区别出表头结点和数据结点return head;}Node * p=new Node(x%10,nullptr);Node * head=transform(x/10);
//-------------------------------单链表头插法 p->next=head->next;head->next=p;
//-------------------------------单链表头插法 return head;
}void traverseReversely(Node * head)//反向遍历单链表
{if(head->next==nullptr)//递归最后一层,到达倒数第二个结点{return;}traverseReversely(head->next);if(head->data!=-1){cout<<head->next->data<<"->";}else{cout<<head->next->data<<endl;}
}int main()
{long long number;while(true){cin>>number;if(number<10 || number>987654321){break;}traverseReversely(transform(number));}return 0;
}
13、水仙花数(再三斟酌)
水仙花数是指一个 n 位数(n≥3),其各位数字的 n 次幂之和等于该数本身。
如:
3^3 + 7^3 + 1^3 = 371
3至9位的水仙花数均以列出,请编程求出100到999999999之间的水仙花数。
3位的水仙花数:153 370 371 407
4位的水仙花数:1634 8208 9474
5位的水仙花数:54748 92727 93084
6位的水仙花数:548834
7位的水仙花数:1741725 4210818 9800817 9926315
8位的水仙花数:24678050 24678051 88593477
9位的水仙花数:146511208 472335975 534494836 912985153
简单明了版
运行时间实在是感人肺腑
#include<iostream>
using namespace std;long long isDaffodil0(long long number)//求n位数number各位数字的 n 次幂之和
{static int length=0;//存储正整数的长度static int length0;//存储正整数的长度,在回归时使用length++;if(number==0)//number得0时,进入递归的最后一层{length0=length-1;//number的长度length多算了一次,所以length减1length=0;//必须在这里归零return 0;}int portion=isDaffodil0(number/10);long long power=1;int x=number%10;for(int i=0;i<length0;i++){power=power*x;}return power+portion;
}bool isDaffodil(long long number)
{return isDaffodil0(number)==number?true:false;//n位数number各位数字的 n 次幂之和是否等于该数本身
}int main()
{for(int i=100;i<999999999;i++){if(isDaffodil(i)){cout<<i<<endl;}}return 0;
}
优化提升版
#include<iostream>
#include<cstring>
using namespace std;long long isDaffodil0(long long number)//求n位数number各位数字的 n 次幂之和
{static int length=0;//存储正整数的长度static int length0;//存储正整数的长度,在回归时使用,接收length的值static long array[10]={0};//10号元素存储数字的长度length++;if(number==0)//number得0时,进入递归的最后一层{length0=length-1;//number的长度length多算了一次,所以length减1length=0;//必须在这里归零if(array[10]!=length0){//10号元素的长度与本次的length0不相等,说明number的长度变化了memset(array,0,sizeof(array));//数组清零array[10]=length0;//10号元素重新赋值}return 0;}int portion=isDaffodil0(number/10);int x=number%10;if(x==0 || x==1)//0的n次方还是0,1的n次方还是1{return x+portion;}if(array[10]==length0 && array[x]!=0){//10号元素的长度与本次的length0相等并且数组中存储了x的n次方return array[x]+portion;}array[x]=1;for(int i=0;i<length0;i++){array[x]=array[x]*x;}//x不为0也不为1,数组中也没有存储x的n次方,单独计算一次return array[x]+portion;
}bool isDaffodil(long long number)
{return isDaffodil0(number)==number?true:false;//n位数number各位数字的 n 次幂之和是否等于该数本身
}int main()
{cout<<"i am excellent"<<endl;for(int i=100;i<999999999;i++){if(isDaffodil(i)){cout<<i<<endl;}}return 0;
}
14、完数
一个数如果恰好等于它的因子之和,这个数就称为 "完数 "。例如:6=1+2+3,求1至10000以内的所有完数。
1至10000以内的所有完数:6、28、496、8128
#include<iostream>using namespace std;int isPerfectNumber0(int x,int begin,int end)
{if(begin>end){return 0;}int temporary=(x%begin==0?begin:0);return temporary+isPerfectNumber0(x,begin+1,end);
}bool isPerfectNumber(int x)
{/*x只要1到x/2范围内的整数进行取余运算即可,只要一次取余运算结果为0,那么x就找到一个因子,就将因子存储在临时变量中只要一次取余运算结果不为0,那么x就没找到因子,就将0存储在临时变量中 之后对这些临时变量进行累加运算,累加和等于x,那么x就为完数,反之则反*/return x==isPerfectNumber0(x,1,x/2);
}int main()
{long long number;for(int i=1;i<=10000;i++){if(isPerfectNumber(i)){cout<<i<<endl;}}return 0;
}
15、回文数
回文数是指正读和反读都相同的数,例如:252、858
求1到100000000(这是一亿)之间的回文数。
要求:每行输出五个数,数与数之间用’\t’隔开。
#include<iostream>
using namespace std;long long isPalindromeNumber0(long long number)//将number逆序组装成一个新整数
{static long long x=0;if(number<=9){//递归的最后一层number=x*10+number;x=0;//静态变量x在最后一层必须要归零return number;}x=x*10+number%10;return isPalindromeNumber0(number/10);
}bool isPalindromeNumber(long long number)
{return number==isPalindromeNumber0(number);
}int main()
{int counter=0;for(int i=1;i<100000000;i++){if(isPalindromeNumber(i)){if(counter==5){cout<<i<<endl;counter=0;continue;}cout<<i<<"\t";counter++;}}return 0;
}
16、16、1+2+3+…+N
输入正整数N(N>1 and N<=1000),求出1、2、3、…、N的和。
输入:3
输出:6
输入:10
输出:55
#include<iostream>
using namespace std;long long summate(long long begin,long long end)
{if(begin==end){return begin;}return begin+summate(begin+1,end);
}int main()
{long long begin=1;long long end;while(true){cin>>end;if(end<1 || end>1000){break;}cout<<summate(begin,end)<<endl;}return 0;
}
17、反转数组
输入正整数N(N>1),再输入N个整数,将其存储在数组中,最后遍历反转后的数组,数与数之间用逗号隔开。
输入:
6
9 10 26 3 13 19
输出:
19,13,3,26,10,9
首尾交换法
#include<iostream>
using namespace std;void input(int * array,int length)//为数组输入数据
{if(length==0){return;}cin>>*array;input(array+1,length-1);
}void traverse(int * array,int length)//遍历数组,数组元素之间用逗号隔开
{if(length==1){cout<<*array<<endl;return;}cout<<*array<<",";traverse(array+1,length-1);
}void reverse(int * array,int length)//反转数组
{if(length==0 || length==1){return;}int temporary=array[0];array[0]=array[length-1];array[length-1]=temporary;reverse(array+1,length-2);
}
int main()
{int length;cin>>length;int array[length]={0};input(array,length);//为数组输入数据cout<<"before reversing:"<<endl;traverse(array,length);//遍历数组cout<<"after reversing:"<<endl;reverse(array,length);//反转数组元素traverse(array,length);//遍历数组return 0;
}
逆序赋值法1
#include<iostream>
using namespace std;void input(int * array,int length)//给数组录入数据
{if(length==0){return;}cin>>0[array];input(array+1,length-1);
}void traverse(int * array,int length)//遍历数组
{if(length==1){cout<<array[0]<<endl;return;}cout<<array[0]<<",";traverse(array+1,length-1);
}void reverse(int * array,int length)//反转数组
{static int * begin=array;//存储数组的首字节指针if(length==0){begin=nullptr;return;}if(begin==nullptr){begin=array;}int temporary=array[length-1];//从后向前存储每个元素的值int * p=begin++;//从前向后存储数组每个元素的首字节指针,即temporary要存储的位置reverse(array,length-1);*p=temporary;
}int main()
{int length;int * array=nullptr;while(true){cin>>length;if(length<=0){break;}array=new int[length];input(array,length);//为数组输入数据reverse(array,length);//反转数组元素traverse(array,length);//遍历数组if(array!=nullptr){delete[] array;}}return 0;
}
逆序赋值法2
#include<iostream>
using namespace std;void input(int * array,int length);//为数组录入数据
void traverse(int * array,int length);//遍历数组
void reverse(int * array,int begin,int end);//反转数组int main()
{int length;int * array;while(true){cin>>length;if(length<=0){break;}array=new int[length];input(array,length);reverse(array,0,length-1);traverse(array,length);}return 0;
}void input(int * array,int length)
{if(length==0){return;}cin>>0[array];input(array+1,length-1);
}void traverse(int * array,in length)
{if(length==1){cout<<*array<<endl;return;}cout<<*array<<',';traverse(array+1,length-1);
}void reverse(int * array,int begin,int end)
{if(begin>end){return;}int index=end-begin;//将元素下标从高到低存储到变量中index中int temporary=array[begin];//按从低到高的下标顺序,读取元素的值并存储在变量中reverse(array,begin+1,end);array[index]=temporary;//回归时,按从低到高的下标顺序,重新给数组元素赋值/*若有数组 int array[8],那么数组下标分别为 0,1,2,3,4,5,6,7令begin=0,end=7,在递归过程中,begin处于递增状态,end保持不变index=end-begin=7-0=7index=end-begin=7-1=6index=end-begin=7-2=5index=end-begin=7-3=4index=end-begin=7-4=3index=end-begin=7-5=2index=end-begin=7-6=1index=end-begin=7-7=0temporary在递归过程中,存储array[0]、array[1]、array[2]、array[3]、array[4]、array[5]、array[6]、array[7]的值。在回归过程中,将temporary的值赋给array[index],temporary依次为 array[7]、array[6]、array[5]、array[4]、array[3]、array[2]、array[1]、array[0],array[index]依次为array[0]、array[1]、array[2]、array[3]、array[4]、array[5]、array[6]、array[7],array[0]装载array[7]的值,array[1]装载array[6]的值,array[2]装载array[5]的值,,,*/
}
18、时间转换1
输入秒数n(n>0),将其转换为时:分:秒的格式输出。
如:
秒数 | 时:分:秒 |
---|---|
1003 | 0:16:43 |
120 | 0:2:0 |
25201319 | 7000:21:59 |
987654321 | 274348:25:21 |
输入:120
输出:0:2:0
#include<iostream>
using namespace std;void convert(long long time)
{static int base=3600;if(base==1){//递归的最后一层base=3600;//base的值必须置为3600cout<<time<<endl;return;}cout<<time/base<<':';time=time%base;base=base/60;convert(time);
/*
起始的基数base是3600,秒数除以base得到小时数,秒数对base取余得到剩余秒数
基数base变成60,剩余秒数除以60得到分数,剩余秒数对base取余得到剩余秒数
基数base变成1,剩余秒数无须再做除法、取余运算了,
*/
}
int main()
{long long time;while(true){cin>>time;if(time<0){break;}convert(time);}return 0;
}
19、时间转换2
我们假定一年为360天,一个月为30天。输入天数N,以Y-M-D的格式输出。
Y是年数、M是月数、D是天数。
如:
天数 | 年-月-天 |
---|---|
25201319 | 70003-7-29 |
1003 | 2-9-13 |
1200 | 3-4-0 |
108000 | 300-0-0 |
7226 | 20-0-26 |
输入:1200
输出:3-4-0
#include<iostream>
using namespace std;void convert(int day)
{static int base=360;if(base==2){cout<<day<<endl;base=360;return;}cout<<day/base<<'-';day=day%base;base=base/12;convert(day);
}int main()
{int day;while(true){cin>>day;if(day<0){break;}convert(day);}return 0;
}
20、N个祝福
输入整数n(0<n<10),输出n个“祝福”。
注:输出中用\t作为间隔符
简单版
输入:
3
输出:
祝福 3
祝福 2
祝福 1
#include<iostream>
using namespace std;void wish(int times)
{if(times==0){return;}cout<<"祝福\t"<<times<<endl;wish(times-1);
}
int main() {int times;cin>>times;wish(times);return 0;
}
困难版
输入:
3
输出:
祝福 1
祝福 2
祝福 3
#include<iostream>
using namespace std;void wish(int times)
{if(times==0){return;}wish(times-1);cout<<"祝福\t"<<times<<endl;
}int main()
{int times;cin>>times;wish(times);return 0;
}
复杂版
输入:
3
输出:
祝福 3
祝福 2
祝福 1
祝福 1
祝福 2
祝福 3
#include<iostream>
using namespace std;void wish(int times)
{if(times==0){return;}cout<<"祝福\t"<<times<<endl;wish(times-1);cout<<"祝福\t"<<times<<endl;}int main()
{int times;cin>>times;wish(times);return 0;
}
21、数组与单链表的转换1(头插法)
输入n(n>0)个整数,存储在数组中,将数组中的数据按原有顺序复制到带表头的单链表中,再遍历单链表。
输入:
8
9 10 26 3 13 20 19 25
输出:
9->10->26->3->13->20->19->25
#include<iostream>
using namespace std;typedef struct node
{int data;struct node * next;
}Node,*NodePointer;NodePointer arrayToLinkedList(int * array,int length)
{if(length==0){Node * head=new Node;head->next=NULL;return head;}Node * p=new Node;p->data=*array;Node * head=arrayToLinkedList(array+1,length-1);p->next=head->next;//头插法head->next=p;//头插法return head;
}void traverseLinkedList(Node * head)
{if(head->next->next==NULL){cout<<head->next->data<<endl;return;}cout<<head->next->data<<"->";traverseLinkedList(head->next);
}void input(int * array,int length)
{if(length==0){return;}cin>>*array;input(array+1,length-1);
}int main()
{int length;cin>>length;int array[length];input(array,length);NodePointer head=arrayToLinkedList(array,length);traverseLinkedList(head);return 0;
}
22、数组与单链表的转换2(尾插法)
输入n(n>0)个整数,存储在数组中,将数组中的数据按相反顺序复制到带表头的单链表中,再遍历单链表。
输入:
5
3 10 26 9 18
输出:
18->9->26->10->3
回归时使用尾插法
#include<iostream>
using namespace std;typedef struct node
{int data;struct node * next;
}Node,*NodePointer;NodePointer arrayToLinkedList(int * array,int length)
{static NodePointer tail=NULL;if(length==0){Node * head=new Node;head->next=NULL;tail=head;return head;}Node * p=new Node;p->data=*array;p->next=NULL;Node * head=arrayToLinkedList(array+1,length-1);tail->next=p;//尾插法tail=p; //尾插法return head;
}void traverseLinkedList(Node * head)//遍历单链表
{if(head->next->next==NULL)//到达倒数第二个结点,即递归的最后一层{cout<<head->next->data<<endl;return;}cout<<head->next->data<<"->";traverseLinkedList(head->next);
}void input(int * array,int length)//为数组录入数据
{if(length==0){return;}cin>>*array;input(array+1,length-1);
}int main()
{int length;cin>>length;int array[length];input(array,length);Node * head=arrayToLinkedList(array,length);traverseLinkedList(head);return 0;
}
前进时使用尾插法
#include<iostream>
using namespace std;typedef struct node
{struct node * next;int data;
}Node,*NodePointer;Node * arrayToLinkedList(int * array,int length)
{static NodePointer tail=NULL;if(length==0){Node * head=new Node;head->next=tail;tail=NULL;return head;}Node * p=new Node;p->data=*array;//尾插法p->next=tail;//尾插法tail=p;//尾插法return arrayToLinkedList(array+1,length-1);
}void traverseLinkedList(Node * head)
{if(head->next->next==NULL){cout<<head->next->data<<endl;return;}cout<<head->next->data<<"->";traverseLinkedList(head->next);
}void input(int * array,int length)
{if(length==0){return;}cin>>*array;input(array+1,length-1);
}int main()
{int length;cin>>length;int array[length];input(array,length);Node * head=arrayToLinkedList(array,length);traverseLinkedList(head);return 0;
}
23、整数与单链表之求和(再三斟酌)
输入两个整数n1、n2,计算两者的和。
(0<n1<=99999999999999999999,0<n2<=99999999999999999999)。
不要数9的个数了,这是20个9。
输入:
99999999999999999999
9
输出:
100000000000000000008
输入:
9876
6789
输出:
16665
输入:
99999999999999999999
99999999999999999999
输出:
199999999999999999998
#include<iostream>
#include<cstring>
using namespace std;
typedef struct node
{char data;struct node * next;
}Node;void reverse(char * source)//反转字符串
{if(*source==0 || *(source+1)==0){return;}int length=strlen(source);char temporary=*source;*source=source[length-1];source[length-1]='\0';reverse(source+1);source[length-1]=temporary;
}Node * summate(char * s1,char * s2)//大数求和
{static int carry=0;//处理加法中的进位Node * p=NULL;if(*s1==0 && *s2==0){//递归的最后一层Node * head=new Node;head->next=NULL;head->data=-1;//因为计算的是两个正整数的和,所以把表头结点的数据域置为-1,作为表头结点的判断依据if(carry!=0){p=new Node;p->data=carry;p->next=head->next;head->next=p;carry=0;}return head;}if(*s1!=0 && *s2!=0){p=new Node;p->data=(*s1-'0')+(*s2-'0')+carry;carry=p->data/10;p->data%=10; }else{p=new Node;p->data=(*s1==0?*s2-'0':*s1-'0')+carry;carry=p->data/10;p->data=p->data%10;}Node * head=summate(*s1==0?s1:s1+1,*s2==0?s2:s2+1);p->next=head->next;//回归的时候用头插法把单链表串起来,低位在前,高位在后head->next=p;return head;
}void traverse(Node * head)
{if(head->next->next==NULL){cout<<(int)head->next->data;return;}traverse(head->next);cout<<(int)head->next->data;if(head->data==-1)//判断是否到达了表头结点{cout<<endl;}
}int main()
{char s1[1024];char s2[1024];Node * head;while(true){cin.getline(s1,1024);cin.getline(s2,1024);if(strcmp(s1,"-1")==0 || strcmp(s2,"-1")==0){break;}reverse(s1);reverse(s2);head=summate(s1,s2);traverse(head);}return 0;
}
24、整数与单链表之阶乘(再三斟酌)
输入一个整数n,求n的阶乘。
基础版阶乘(0<n<10)
输入:5
输出:120
输入:10
输出:3628800
#include<iostream>
using namespace std;
long getFactorial(int number)
{if(number==2 || number==1){return number;}return number*getFactorial(number-1);
}int main()
{int number;while(true){cin>>number;if(number>=1 && number<=10){cout<<getFactorial(number)<<endl;}else{break;}}return 0;
}
升级版阶乘(0<n<100)
输入:20
输出:2432902008176640000
输入:30
输出:265252859812191058636308480000000
#include<iostream>
using namespace std;typedef struct node{int data;struct node * next;
}Node;void multiply0(Node * head,int x);//使用单链表进行乘法运算
void multiply(Node * head,int x);//单链表是否为空,分两种情况处理乘法运算
void traverse(Node * head);//遍历单链表
Node * makeFactorial(int x);//大数阶乘,返回表头结点指针
void destroy(Node * head);//销毁单链表int main()
{long x;Node * head=NULL;while(true){cin>>x;if(x<=0){break;}head= makeFactorial(x);traverse(head);//(倒序)遍历单链表destroy(head);//销毁单链表}return 0;
}void traverse(Node * head)
{if(head==NULL){return;}traverse(head->next);head->data==-1?cout<<endl:cout<<head->data;
}Node * makeFactorial(int x)
{if(x==1){Node * head=new Node;head->next=NULL;head->data=-1;return head;}Node * head=makeFactorial(x-1);multiply(head,x);return head;
}void multiply(Node * head,int x)
{if(head->next==NULL)//若单链表的表头结点指针域为空{while(x>0){Node * p=new Node;p->next=NULL;p->data=x%10;head->next=p;head=p;x=x/10;}}else//若单链表的表头结点指针域不为空{multiply0(head->next,x);//表头结点不参与乘法运算}
}void multiply0(Node * head,int x)
{static int carry=0;//存储乘法运算产生的进位static Node * predecessor=NULL;//存储结点的前驱结点指针if(head==NULL)//在递归最后一层处理遗留的进位{Node * p;while(carry>0)//处理进位{p=new Node;p->data=carry%10;p->next=NULL;predecessor->next=p;predecessor=p;carry/=10;//整型变量carry在递归最后一层也要归零,这里在循环中处理掉了}predecessor=NULL;//指针变量归零return;}
//--------------------------------------------首结点到尾结点都与x进行了乘法运算int result=head->data*x+carry;head->data=result%10;carry=result/10;
//--------------------------------------------首结点到尾结点都与x进行了乘法运算predecessor=head;//存储当前结点指针,实则存储下一结点的前驱结点指针multiply0(head->next,x);
}void destroy(Node * head)//销毁单链表
{if(head==NULL){return;}destroy(head->next);//cout<<"销毁单链表其中结点\t"<<head->data<<endl;delete head;
}
25、双向循环链表之约瑟夫环(再三斟酌)
n个小朋友围成一圈,从第一个小朋友自1开始顺序报数,数到淘汰数x的小朋友出圈,再由下一个小朋友重新从 1开始报数,数到淘汰数 x的小朋友再出圈,依次类推,直到剩下一个小朋友,求该小朋友的编号m。
输入n和x,求m。
测试数据:
人数 | 淘汰数 | 最后一人编号 |
---|---|---|
10 | 3 | 4 |
85 | 9 | 38 |
100 | 55 | 85 |
68 | 7 | 68 |
70 | 6 | 51 |
90 | 9 | 83 |
55 | 8 | 29 |
输入:10 3
输出:4
#include<iostream>using namespace std;
typedef struct node {int data;struct node *prior;struct node *next;
} Node;//按照number的大小生成number个结点,生成带表头的双向循环链表,结点的数据依次为1、2、3...
Node *generate(int number);
//传入尾结点指针,遍历双向循环链表
void traverse(Node *tail);
//销毁双向循环链表
void destroy(Node * tail);
//约瑟夫环,自1报数并移除结点
Node * remove(Node *head, int target);int main() {int number;int target;Node *tail = NULL;while (true) {cin >> number;cin >> target;if (number <= 0 || target<=0) {break;}tail = generate(number);//traverse(tail);tail=remove(tail->next,target);cout<<tail->data<<endl;destroy(tail);}return 0;
}Node * remove(Node *head, int target)
{static int counter = 0;//用于报数,存储每次报到的数if (head->next->next == head && head->prior->prior==head)//递归最后一层{//只剩表头结点、一个数据结点,那么指针变量head是指向表头结点、还是指向尾结点呢?依淘汰数target而定counter = 0;return head->data==-1?head->next:head;//返回尾结点指针}if (head->data != -1)//非表头结点才报数,遇表头结点不报数{counter++;//报数if (counter == target) //报到指定的淘汰数{counter = 0;//归零,下次报数自1开始head->prior->next = head->next;//当前结点的前驱结点后指针域指向当前结点的后继结点head->next->prior = head->prior;//当前结点的后继结点前指针域指向当前结点的前驱结点Node *p = head;//存储当前结点的指针head = head->prior;//存储当前结点的前驱结点指针delete p;//释放当前结点}}remove(head->next, target);
}void destroy(Node * tail)
{if(tail->data==-1)//递归最后一层,到达表头结点{delete tail;return;}Node * p=tail->prior;delete tail;destroy(p);
}void traverse(Node *tail) {if (tail->data == -1) {return;}traverse(tail->prior);if (tail->next->data == -1) {//判断是否为尾结点,尾结点的后继结点为表头结点,而表头结点的数据为-1cout << tail->data << endl;} else {cout << tail->data << "->";}
}Node *generate(int number) {if (number == 0) {//递归最后一层Node *head = new Node;head->data = -1;head->next = NULL;head->prior = NULL;return head;}Node *successor = new Node;//创建新结点successor->data = number;Node *predecessor = generate(number - 1);if (predecessor->next == NULL && predecessor->prior == NULL)//表头结点{//递归倒数第二层predecessor->next = successor;predecessor->prior = successor;successor->prior = predecessor;successor->next = predecessor;} else//非表头结点,做追加尾结点操作{successor->prior = predecessor;//新结点的前指针域指向尾结点successor->next = predecessor->next;//新结点的后指针域指向表头结点predecessor->next = successor;//原先的尾结点后指针域指向新结点}return successor;//返回最新的尾结点指针
}
26、隔壁是偶数
输入整数n(n>0 and n<16),再输入n个正整数。在n个正整数中,若某些数的隔壁均是偶数,请依次输出换行。第一个正整数与最后一个正整数无须考虑。
输入:
10
13 19 10 9 26 3 25 20 88 18
输出:
9
88
输入:
6
13 25 19 20 15 10
输出:
15
顺序表版
#include<iostream>using namespace std;void input(int *array, int length);//给定数组首字符指针、数组长度,录入数据
void neighborNumber(int *array, int length);//求出隔壁为偶数的数int main() {int length;cin >> length;int *array = new int[length];input(array, length);neighborNumber(array, length);return 0;
}void neighborNumber(int *array, int length) {if (length == 2)//首元素和尾元素不考虑,所以长度length减去2{return;}neighborNumber(array, length - 1);/*假设length=8,那么可能满足条件的元素所在的下标依次为1、2、3、4、5、6下标为0、7的元素是不满足条件的,所以不参与条件判断函数向下递归的时候,length在每一层的值分别为8、7、6、5、4、3、2(这里的2出现在最后一层)length的值与我们所需的元素下标是不符的,经过推算得知length-2是符合的如:8、7、6、5、4、36、5、4、3、2、1*///cout<<array[length-2]<<"---";if (array[length - 2 - 1] % 2 == 0 && array[length - 2 + 1] % 2 == 0) {cout << array[length - 2] << endl;}}void input(int *array, int length) {if (length == 0) {return;}cin >> *array;input(array + 1, length - 1);
}/*
10
13 19 10 9 26 3 25 20 88 189
88
----------------------------------
5
98 150 88 900 20150
88
900
----------------------------------
6
13 25 19 20 15 1015
----------------------------------
15
82 19 10 9 26 3 28 20 10 18 13 87 10 3 5819
9
3
20
10
3*/
双链表版
#include<iostream>using namespace std;
struct Node {int data;Node * prior;Node * next;Node():data(),prior(),next(){}//空参构造函数Node(int data, Node * prior,Node * next) : data(data), prior(prior),next(next) {}
};Node * input(int length);//根据长度生成相应个结点的带表头双向链表,返回表头结点指针
void neighborNumber(Node * head);求出隔壁为偶数的数int main()
{int length;cin>>length;Node * head=input(length);neighborNumber(head);return 0;
}Node * input(int length)//根据长度生成相应个结点的带表头双向链表,返回表头结点指针
{if(length==0){Node * head=new Node(-1,NULL,NULL);return head;}Node * p=new Node;cin>>p->data;Node * head= input(length-1);if(head->prior==NULL && head->next!=NULL)//非空双链表{//双链表头插法插入结点p->prior=head;p->next=head->next;head->next->prior=p;head->next=p;}else//空双链表,只有表头结点{//双链表头插法插入结点p->prior=head;p->next=head->next;head->next=p;}return head;
}void neighborNumber(Node * head)
{if(head->next==NULL)//尾结点不进行筛选,在递归的最后一层将尾结点作为结束条件{return;}if(head->prior!=NULL && head->prior->prior!=NULL)//表头结点、首结点不进行筛选{if(head->prior->data%2==0 && head->next->data%2==0){cout<<head->data<<endl;}}neighborNumber(head->next);
}
27、字符串的长度
输入一字符串,求其长度。需手写函数,不得另外调用函数。
输入:YouAreMyFire
输出:12
#include<iostream>
using namespace std;int lengthOfString(char * source)//求字符串长度
{if(*source){return 1+lengthOfString(source+1);}return 0;
}int main()
{char string[1024];cin.getline(string,1024);cout<<lengthOfString(string);return 0;
}
28、英文语句中单词的个数
输入一英文语句,求语句中有多少个单词。
输入:Hello!I’m Lisa. How are you doing?
输出:8
#include<iostream>
#include<cstring>
using namespace std;int count(char * string);//统计英文语句中单词的个数
bool isLetter(char target);//判断字符是否为字母int main()
{char string[1024]={0};while(true){cin.getline(string,1024);cout<<count(string)<<endl;if(strcmp(string,"exit")==0 || strcmp(string,"quit")==0){break;}}return 0;
}int count(char * string)//统计英文语句中单词的个数
{if(*string==0)//到达字符结束符{//递归最后一层return 0;}if(isLetter(string[0]) && !isLetter(string[1])){//当前字符为字母,而后继字符非字母,表明出现了一个单词return 1+count(string+1);}return 0+count(string+1);//未出现单词
}bool isLetter(char target)//判断字符是否为字母
{return (target>='a' && target<='z')||(target>='A' && target<='Z');
}
29、每个字母出现的次数
输入一单词,求单词中每个字母出现的次数。
注:输出时,按字母顺序来,并且小写字母排在前,大写字母排在后。
输入:Pepper
输出:
e 2
p 2
r 1
P 1
#include<iostream>
#include<cstring>
using namespace std;void shine(char * source)
{static int letter[52]={0};/*下标0~25的空间存储各小写字母的出现次数下标26~51的空间存储各大写字母的出现次数*/if(*source=='\0'){//递归最后一层,输出结果for(int i=0;i<52;i++){if(i<26 && letter[i]>0){cout<<(char)('a'+i)<<'\t'<<letter[i]<<endl;}else if(i>=26 && letter[i]>0){cout<<(char)('A'+i-26)<<'\t'<<letter[i]<<endl;}}memset(letter,0,52*sizeof(int));//数组清零return;}letter[(*source>='a'&& *source<='z')?*source-'a':*source-'A'+26]++;/*推算字母所对应的下标若为小写字母,*source-'a'可以推算出下标0,1,2,,,25若为大写字母,*source-'A'+26可以推算出下标26,27,,,51*/shine(source+1);
}int main()
{char string[1024]={0};while(true){cin.getline(source,1024);if(strcmp(string,"exit")==0 || strcmp(string,"quit")==0){break;}shine(source);}return 0;
}
30、字符串中出现多少个数字
输入一字符串,求字符串中有多少个数字。
输入:
1319 YouAreMyFire 1314 2520
输出:
12
#include<iostream>
using namespace std;int shine(char * source)
{if(*source==0){return 0;}return ((*source>='0' && *source<='9')?1:0)+shine(source+1);
}int main()
{char source[1024]={0};cin.getline(source,1024);cout<<shine(source)<<endl;return 0;
}
31、字符串中有多少个字母
输入一字符串,求字符串中有多少个字母。
输入:We Are Astronaut.Go ahead!
输出:21
#include<iostream>
using namespace std;int shine(char * source)
{if(*source==0){return 0;}int counter=((*source>='a' && *source<='z') || (*source>='A' && *source<='Z'))?1:0;return counter+shine(source+1);
}int main()
{char array[1024]={0};cin.getline(array,1024);cout<<shine(array);return 0;
}
32、英文语句中每个单词的长度
输入一英文语句,按照单词的输入顺序求出每个单词的长度,重复的单词算多个单词。
输入:Never give up!
输出:
Never 5
give 4
up 2
#include<iostream>
#include<cstring>
using namespace std;void shine(char * begin);//字符串中每个单词的长度
bool isLetter(char target);//当前字符是否为字母int main()
{char source[1024]={0};while(true){cin.getline(source,1024);if(strcmp(source,"exit")==0 || strcmp(source,"quit")==0){break;}shine(source);}return 0;
}void shine(char * begin)//字符串中每个单词的长度
{static int counter=0;if(*begin==0){return;}if(isLetter(*begin)){cout<<*begin;counter++;}if(isLetter(begin[0]) && !isLetter(begin[1])){cout<<' '<<counter<<endl;counter=0;}shine(begin+1);
}bool isLetter(char target)//当前字符是否为字母
{return (target>='A' && target<='Z')||(target>='a' && target<='z');
}
33、字符串中最长的单词
输入一英文句子,按照单词的输入顺序求出最长的单词以及长度。
输入:
exceptional,gorgeous,transcendent and diligent life
输出:
transcendent 12
#include<iostream>
#include<cstring>
using namespace std;struct Node
{char * source;short length;Node * next;Node(char * source,short length,Node * next){this->source=source;this->length=length;this->next=next;}
};//单链表结点bool isLetter(char target);//判断字符是否为字母
Node * extract(char * source);//将字符串中所有单词、单词长度存储到无表头单链表
void traverse(Node * predecessor);//遍历无表头单链表 仅测试用
Node * getMaximum(Node * predecessor);//取出最长单词所在的结点的指针int main()
{char source[1024]={0};Node * predecessor=nullptr;Node * result=nullptr;while(true){cin.getline(source,1024);if(strcmp(source,"exit")==0 || strcmp(source,"quit")==0){break;}predecessor=extract(source);result=getMaximum(predecessor);for(char * begin=result->source;isLetter(*begin);begin++){cout<<*begin;}cout<<'\t'<<result->length<<endl;}return 0;
}bool isLetter(char target)
{return (target>='A' && target<='Z')||(target>='a' && target<='z');
}Node * extract(char * source)
{static short length=0;if(*source==0){length=0;//return nullptr;}if(isLetter(*source))//碰到字母,统计一次长度length{length++;}if(isLetter(source[0]) && !isLetter(source[1])){/*碰到字母,且字母后面不是字母,表明一个单词的拼写完成,将单词的首字母指针、单词的长度存储进单链表结点中长度length归零,对下一个单词的长度进行统计*/Node * p=new Node(source-length+1,length,nullptr);length=0;Node * successor=extract(source+1);p->next=successor;//无表头结点的单链表头插法return p;} //这里的非字母字符没有进行处理return extract(source+1);
}void traverse(Node * predecessor)
{if(predecessor==nullptr){return;}for(char * ch=predecessor->source;isLetter(*ch);ch++){cout<<*ch;}cout<<endl;traverse(predecessor->next);
}Node * getMaximum(Node * predecessor)
{if(predecessor->next==nullptr){return predecessor;}Node * successor=getMaximum(predecessor->next);return predecessor->length>successor->length?predecessor:successor;
}
34、翻转字符串
输入一字符串,按照原有顺序逆序输出。
输入:
31 U evoL I
输出:
I Love U 13
首尾交换(再三斟酌)
#include<iostream>
#include<cstring>
using namespace std;int lengthOfString(char * source);//求字符串长度
void reverse(char * source);//反转字符串int main()
{char source[1024]={0};int length=sizeof(source)/sizeof(char);while(true){cin.getline(source,length);if(strcmp(source,"quit")==0 || strcmp(source,"exit")==0){break;}reverse(source);cout<<source<<endl;}return 0;
}
int lengthOfString(char * source)//求字符串长度
{if(*source==0){return 0;}return 1+lengthOfString(source+1);
}void reverse(char * source)//反转字符串
{if(lengthOfString(source)==1 || lengthOfString(source)==0){return;}int length=lengthOfString(source);char temporary=source[length-1];source[length-1]='\0';reverse(source+1);/*将尾字符置为'\0',整型变量length在下一次递归中就会少一个1指针变量source的累加,整型变量length在下一次递归中就会再少一个1length越来越小,直至length=1(字符串长度为奇数)或length=0(字符串长度为偶数)看着有点复杂,其实是首尾交换*/source[length-1]=source[0];source[0]=temporary;
}
逆序赋值法(再三斟酌)
将数组每个元素中的值依次读取并一字排开,再将数组每个元素的指针反向一字排开,最后把值重新赋给对应的元素。
#include<iostream>
#include<cstring>
using namespace std;void reverse(char * source);//反转字符串
void reverse0(char * source,short begin,short end);//反转字符串的核心int main()
{char source[1024]={0};while(true){cin>>source;if(strcmp(source,"exit")==0 || strcmp(source,"quit")==0){break;}reverse(source);cout<<source<<endl;}return 0;
}
void reverse(char * source)//反转字符串
{if(strlen(source)==1){return;}int length=strlen(source);reverse0(source,0,length-1);
}
void reverse0(char * source,short begin,short end)//反转字符串的核心
{
/* 没有数组首尾元素之间的交换,直接将数组指针倒转,把字符存储在指针所指向的数组元素中begin,end分别是所要操作的数组元素的首尾下标,给begin、end传递参数时,要注意begin<end,begin>=0,end<strlen(source)position=end-begin的计算由来假充需要操作的数组元素下标为0,1,2,3,4,5,6,7则begin=0,end=7变量begin在递归过程中是不断累加的,变量end递归过程中是不变的0号元素存储到7号元素中,position=end-begin=7-0=71号元素存储到6号元素中,position=end-begin=7-1=62号元素存储到5号元素中,position=end-begin=7-2=53号元素存储到4号元素中,position=end-begin=7-3=44号元素存储到3号元素中,position=end-begin=7-4=35号元素存储到2号元素中,position=end-begin=7-5=26号元素存储到1号元素中,position=end-begin=7-6=17号元素存储到0号元素中, position=end-begin=7-7=0故position=end-begin
*/if(begin>end){return;}int position=end-begin;//当前字符将要存储的数组空间下标char temp=source[begin];//存储当前字符reverse0(source,begin+1,end);source[position]=temp;//回归时将当前字符存储到指定的数组空间中
}
35、翻转字符串中的单词1
输入一字符串,字符串由若干个单词、空格组成,按照单词在字符串中的原有顺序逆序输出,单词与单词之间用空格隔开。
输入:Fire My Are You
输出:You Are My Fire
注:在本题中,使用了带表头单链表,先将每个单词的首字节指针存储在结点的数据域中,再逆序遍历单链表即完成要求。
#include<iostream>
#include<cstring>
using namespace std;struct Node
{char * source;Node * next;Node(char * source,Node * next):source(source),next(next){}
};bool isLetter(char target);//判断字符是否为字母
Node * extract(char * source);//将字符串中的单词提取出来,形成带表头单链表
void traverseReversely(Node * head);//逆序遍历带表头单链表
void traverse(char * source);//遍历字符串中的单词,单词的结束符为空格或'\0'
void destroy(Node * head);//销毁带表头单链表
int main()
{char source[1024]={0};while(true){cin.getline(source,1024);//不能写成 cin>>sourceif(strcmp(source,"exit")==0 || strcmp(source,"quit")==0){break;}Node * head=extract(source);traverseReversely(head);destroy(head);}return 0;
}Node * extract(char * source)//将字符串中的单词提取出来,形成带表头单链表
{static int length=0;if(*source=='\0'){//到达递归最后一层length=0;//静态变量length在递归最后一层必须归零,以便在程序运行过程中保证数据的正确性Node * head=new Node(nullptr,nullptr);//生成表头结点return head;//返回表头结点指针}if(isLetter(*source)){length++;}if(isLetter(*source) && (source[1]==' ' || source[1]=='\0')){//完成一个单词的拼写Node * p=new Node(source-length+1,nullptr);//创建单链表结点,将单词所在空间的首字节指针存储其中length=0;//为计算下一个单词的长度,单词的长度length归零Node * head=extract(source+1);//返回表头结点指针p->next=head->next;//单链表头插法head->next=p;//单链表头插法return head;}return extract(source+1);
}void traverseReversely(Node * head)//逆序遍历带表头单链表
{if(head->next==nullptr) {//递归最后一层,每个结点的数据都由其前驱结点进行处理,所以尾结点自然成为递归边界return;}traverseReversely(head->next);traverse(head->next->source);/*for(char * source=head->next->source;*source!=' ' && *source!='\0';source++){cout<<*source;}*/if(head->source!=nullptr)//回归时遇到数据结点{cout<<' ';}else//回归到表头结点{cout<<endl;}
}void traverse(char * source)//遍历字符串,字符串的结束符为空格或'\0'
{if(*source==' ' || *source=='\0'){return;}cout<<*source;traverse(source+1);
}bool isLetter(char target)//判断字符是否为字母
{return (target>='a' && target<='z') || (target>='A' && target<='Z');
}void destroy(Node * head)//销毁带表头单链表
{if(head==nullptr){return;}destroy(head->next);delete head;
}
36、翻转字符串中的单词2
输入一字符串,字符串由若干个单词、空格、逗号、句号等等字符组成,按照单词在字符串中的原有顺序逆序输出,每输出一个单词进行一次换行。
输入:
Hello,I am Hannah.
输出:
Hannah
am
I
Hello
指针版
#include<iostream>
#include<cstring>
using namespace std;void extract(char * source);//找出字符串中所有的单词,并以原有顺序逆序输出
bool isLetter(char target);//判断字符是否为字母
void traverse(char * source);//遍历单词,结束条件为遇到非字母字符
int main()
{char source[1024]={0};while(true){cin.getline(source,1024);if(strcmp(source,"exit")==0 || strcmp(source,"quit")==0){break;}extract(source);}return 0;
}void extract(char * source)
{static int length=0; //计算单词长度的变量if(*source=='\0')//递归结束条件{length=0;return;}if(isLetter(*source)){length++;}if(isLetter(source[0]) && !isLetter(source[1]))//一个单词拼写完毕{char * begin=source-length+1;//单词的起始指针length=0;//计算单词长度的变量length清零,以便计算下一个单词的长度extract(source+1);traverse(begin);//回归时再遍历单词return;//这个return不能少,否则会导致递归方向错误}extract(source+1);
}bool isLetter(char target)
{return (target>='a' && target<='z') || (target>='A' && target<='Z');
}void traverse(char * source)//遍历单词,结束条件为遇到非字母字符
{if(!isLetter(*source)){cout<<endl;return;}cout<<*source;traverse(source+1);
}
单链表版
#include <iostream>
#include<cstring>
using namespace std;struct Node
{char * begin;Node * next;Node(char * begin,Node * next):begin(begin),next(next){}
};Node * extract(char * source);//将所有的单词的首字母指针存储在带表头的单链表中,返回表头结点指针
bool isLetter(char target);//判断字符是否为字母
void traverseLinkedList(Node * head);//遍历带表头单链表
void traverseString(char * source);//遍历单词,结束条件为遇到非字母字符
int main()
{char source[1024]={0};Node * head;while(true){cin.getline(source,1024);if(strcmp(source,"exit")==0 || strcmp(source,"quit")==0){break;}head=extract(source);traverseLinkedList(head);}return 0;
}Node * extract(char * source)
{static int length=0; //计算单词长度的变量if(*source=='\0')//递归结束条件{length=0;Node * head=new Node(nullptr,nullptr);return head;}if(isLetter(*source)){length++;}if(isLetter(source[0]) && !isLetter(source[1]))//一个单词拼写完毕{Node * p=new Node(source-length+1,nullptr);//把单词首字母指针存储在结点中length=0;//计算单词长度的变量length清零,以便计算下一个单词的长度Node * head=extract(source+1);p->next=head->next;//带表头单链表头插法head->next=p;//带表头单链表头插法return head;}return extract(source+1);
}bool isLetter(char target)//判断字符是否为字母
{return (target>='a' && target<='z') || (target>='A' && target<='Z');
}void traverseLinkedList(Node * head)//遍历带表头单链表
{if(head->next==nullptr)//尾结点的数据由其前驱结点进行输出,所以到达尾结点时,递归结束{//递归最后一层return;}traverseLinkedList(head->next);traverseString(head->next->begin);
}void traverseString(char * source)//遍历单词
{if(!isLetter(*source))//遇到非字母字符,到达递归边界{cout<<endl;return;}cout<<*source;traverseString(source+1);
}
37、删除字符串中的字符
输入任意字符串,再给定一个字符,将该字符从字符串中移除,最后将处理后的字符串输出。
输入:
U9Are9My9Love
9
输出:
UAreMyLove
静态变量完成递归操作
#include<iostream>
using namespace std;void remove(char * source,char target);//删除字符串所有的target字符int main()
{char source[1024]={0};char target;while(true){cin.getline(source,1024);cin.get(target);remove(source,target);cout<<source<<endl;cin.get();//接收上一行的回车符}return 0;
}void remove(char * source,char target)//删除字符串所有的target字符
{static char * begin=source;if(*source=='\0'){*begin=*source;begin=nullptr;//将begin置空,便于在程序运行过程中,对该函数的再次调用return;}if(begin==nullptr){begin=source;}if(*source!=target){*begin=*source;begin++;}remove(source+1,target);
}
添加函数、形式参数完成递归操作
#include<iostream>
using namespace std;void remove(char * source,char target);//删除字符串所有的target字符
void remove0(char * source,char * destination,char target);//删除字符串所有的target字符int main()
{char source[1024]={0};char target;while(true){cin.getline(source,1024);cin.get(target);remove(source,target);cout<<source<<endl;cin.get();//接收上一行的回车符}return 0;
}void remove(char * source,char target)//删除字符串所有的target字符
{char * destination=source;remove0(source,destination,target);
}
void remove0(char * source,char * destination,char target)//删除字符串所有的target字符
{//将一个字符数组当成两个字符数组来处理if(*source=='\0'){//递归最后一层*destination=*source;return;}if(*source!=target){*destination=*source;remove0(source+1,destination+1,target);}else{remove0(source+1,destination,target);}
}
38、字符串中的数1
任意输入一个字符串,其中有整数(>0)、其它字符。从字符串中筛选出整数,并依次输出,每输出一个整数进行一次换行。
如:字符串”How1319Gorgeous2520!1015”中的整数有1319、2520、1015
输入:
How1319Gorgeous2520!1015
输出:
1319
2520
1015
#include<iostream>
using namespace std;bool isNumber(char target);//判断字符是否为数字
void extract(char * begin);//筛选出字符串中的整数(>0)int main()
{char * begin=new char[1024];cin.getline(begin,1024);extract(begin);return 0;
}void extract(char * begin)//筛选出字符串中的整数(>0)
{if(*begin==0){return;}if(isNumber(*begin)){cout<<*begin;}if(isNumber(*begin) && !isNumber(*(begin+1))){cout<<endl;}extract(begin+1);
}bool isNumber(char target)//判断字符是否为数字
{return target>='0' && target<='9';
}
39、字符串中的数2
任意输入一个字符串,其中有整数(0<=n<=123456789)、其它字符。从字符串中筛选出整数,并依次输出,两两之间用加号隔开。再将这些整数求和,输出结果。
输入:
How1319Gorgeous2520!60
输出:
1319+2520+60
3899
输入:
You1Are9The10Champion500
输出:
1+9+10+500
520
#include<iostream>
#include<cstring>
using namespace std;struct Node
{int data;Node * next;Node(int data,Node * next=nullptr):data(data),next(next){}
};//单链表结点Node * extract(char * source);//提取字符串中的整数并将其存储到带表头单链表,返回表头结点指针
bool isDigit(char target);//判断字符是否为数字
int traverseAndSummate(Node * head);//遍历单链表并求和,返回求和结果
int main()
{char source[1024]={0};while(true){cin.getline(source,1024);if(strcmp(source,"0")==0){break;}Node * head=extract(source);traverseAndSummate(head);}return 0;
}Node * extract(char * source)
{static int integer=0;//存储整数if(*source=='\0'){integer=0;//将integer置为0,保证函数在程序运行中的数据正确性Node * head=new Node(-1,nullptr);//创建表头结点return head;}if(isDigit(*source))//遇到数字字符,将其转换为整数,并将其存储到integer中{integer=integer*10+*source-'0';}if(isDigit(source[0]) && !isDigit(source[1])){//遇到数字字符且下一个字符不是数字字符,将integer存储到单链表中Node * p=new Node(integer,nullptr);integer=0;//将integer置为0,为提取下一个整数做准备Node * head=extract(source+1);p->next=head->next;//单链表头插法head->next=p;//单链表头插法return head; }return extract(source+1);
}int traverseAndSummate(Node * head)//遍历单链表并求和
{if(head->next==nullptr)//到达最后一个结点即递归边界,开始回归{return head->data;//返回尾结点的值}if(head->next->next!=nullptr)//递归未到达倒数第二个结点{cout<<head->next->data<< '+';}else//递归到达倒数第二个结点{cout<<head->next->data<<endl;}int sum=traverseAndSummate(head->next);if(head->data!=-1){//未回归到第一个结点return sum+head->data;}else{//回归到第一个结点即递归第一层cout<<sum<<endl;return sum;}
}bool isDigit(char target)//判断字符是否为数字
{return target>='0' && target<='9';
}
40、字符串中的数3
任意输入一个字符串,其中有整数(0<=n<=123456789)、其它字符。从字符串中筛选出所有整数,输出这些整数升序排序的结果、降序排序的结果。
如:字符串“13I’m19Here15The25DawnIs20Coming10”中的整数有13、19、15、25、20、10,升序排序后的结果为10、13、15、19、20、25,降序排序的结果为25、20、19、15、13、10
注:此题目中使用双链表完成此题,涉及到的双链表操作有插入排序、正反遍历、销毁链表,这些操作都是使用递归完成。
输入:
13I’m19Here15The25DawnIs20Coming10
输出:
10 13 15 19 20 25
25 20 19 15 13 10
输入:
How1319Gorgeous2520!61Happy1925AmI
输出:
61 1319 1925 2520
2520 1925 1319 61
输入:
What 2090 creature 5010!2025I’m9095 1949shocked.9125
输出:
1949 2025 2090 5010 9095 9125
9125 9095 5010 2090 2025 1949
#include<iostream>
#include<cstring>
using namespace std;struct Node
{int data;Node * prior;Node * next;Node(int data,Node * prior=nullptr,Node * next=nullptr):data(data),prior(prior),next(next){}
};Node * extract(char * source);//从字符串中提取整数并将其存储到带表头双链表中,返回双链表表头结点指针
bool isDigit(char target);//判断字符是否为数字字符
void traverse(Node * head);//正向、反向遍历双链表并输出
void insert(Node * head,Node * p);//寻找新结点的插入位置并插入新结点,使双链表按升序排列
void destroy(Node * head);//销毁带表头双链表
int main()
{char source[1024]={0};Node * head=nullptr;while(true){cin.getline(source,1024);if(strcmp(source,"0")==0){break;}head=extract(source);traverse(head);destroy(head);}return 0;
}Node * extract(char * source)
{static int x=0;//用于存储整数if(*source=='\0')//到达字符串末尾即递归边界{x=0;//将x置为0,保证函数在程序运行中多次调用下的数据正确性Node * head=new Node(-1,nullptr,nullptr);//创建双链表表头结点return head;}if(isDigit(*source))//遇到数字字符{x=x*10+*source-'0';//将其转换为整数,并将其存储到x中}if(isDigit(source[0]) && !isDigit(source[1]))//遇到数字字符且下一个字符不是数字字符{Node * p=new Node(x,nullptr,nullptr);//将x存储到双链表结点中x=0;//将x置为0,为提取下一个整数做准备Node * head=extract(source+1);if(head->prior==nullptr && head->next==nullptr)//表头结点的前后指针域为空即遇到空双链表{//递归的倒数第二层p->prior=head;//新结点的前指针域指向表头结点p->next=head->next;//新结点的后指针域置为空(其实表头结点的后指针域在此时也为空)head->next=p;//表头结点的后指针域指向新结点}else{insert(head,p);//寻找新结点的插入位置并插入新结点}return head;//返回表头结点指针}return extract(source+1);
}void insert(Node * head,Node * p)//寻找新结点的插入位置并插入新结点,使双链表按升序排列
{if(head->data>p->data)//找到一个插入位置,该位置位于表头结点之后,尾结点之前{p->prior=head->prior;p->next=head;head->prior->next=p;head->prior=p;return;}if(head->next==nullptr)//找到另一个插入位置,该位置位于尾结点之后{p->prior=head;p->next=head->next;head->next=p;return;}/*上面两个if语句的顺序不能颠倒,否则会出现错误在表头结点之后尾结点之前没有找到新结点插入的位置,才会到尾结点后面追加新结点两个if语句都是递归边界,在表头结点之后尾结点之前找到新结点插入的位置时,插入新结点,终止递归在尾结点之前没有找到新结点插入的位置,就在尾结点后面追加新结点,终止递归这里把表头结点也当作了一个数据结点,进行了排序,而表头结点的数据域为-1,始终排在第一位,不影响排序结果使用到的算法是插入排序*/insert(head->next,p);
}void traverse(Node * head)//正向、反向遍历双链表
{if(head==nullptr || head->next==nullptr){return;}head->next->next!=nullptr?cout<<head->next->data<<" ":cout<<head->next->data<<endl; traverse(head->next);head->prior!=nullptr?cout<<head->next->data<<" ":cout<<head->next->data<<endl;
}bool isDigit(char target)//判断字符是否为数字
{return target>='0' && target<='9';
}void destroy(Node * head)//销毁带表头双向链表
{if(head==nullptr){return;}destroy(head->next);delete head;
}