递归40题!再见递归
简介: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);//创建表头结点,为区别出表头结点,将表头结点的值置为-1
return 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减1
length=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减1
length=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=7
index=end-begin=7-1=6
index=end-begin=7-2=5
index=end-begin=7-3=4
index=end-begin=7-4=3
index=end-begin=7-5=2
index=end-begin=7-6=1
index=end-begin=7-7=0
temporary在递归过程中,存储
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的值必须置为3600
cout<<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) {
//判断是否为尾结点,尾结点的后继结点为表头结点,而表头结点的数据为-1
cout << 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、3
6、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 18
9
88
----------------------------------
5
98 150 88 900 20
150
88
900
----------------------------------
6
13 25 19 20 15 10
15
----------------------------------
15
82 19 10 9 26 3 28 20 10 18 13 87 10 3 58
19
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在下一次递归中就会再少一个1
length越来越小,直至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=7
1号元素存储到6号元素中,position=end-begin=7-1=6
2号元素存储到5号元素中,position=end-begin=7-2=5
3号元素存储到4号元素中,position=end-begin=7-3=4
4号元素存储到3号元素中,position=end-begin=7-4=3
5号元素存储到2号元素中,position=end-begin=7-5=2
6号元素存储到1号元素中,position=end-begin=7-6=1
7号元素存储到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>>source
if(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;
}