[ 注意:前6道题均是使用递归完成的,需要数组、指针、链表相关知识,第7道题是求水仙花数的加强版,也是使用递归完成的,3位数的水仙花数我们很熟悉,那5位数的呢?7位数的呢?9位数的呢?怎么把3位到9位数的水仙花数一起求出来呢?没错,使用递归!]
1.数组转链表之一
1)将一个int[ ]型数组中的各个元素依次存储到(不带表头)单链表中
2)遍历单链表
typedef struct node
{
struct node * next;
int data;
}Node,*NodePointer;
//不带表头结点(即首元结点,也即头结点,这三各种称呼的意思不明确,自己要知道咋回事)
NodePointer copy(int * array,int length)//把数组中的各个元素依次存储到单链表各个结点中
{
if(length==0)//数组遍历完成,开始回归
{
return NULL; //返回最后一个结点的指针域的值NULL
}
NodePointer p=new Node;//创建单链表的结点
p->data=*array;//依次将数组中的元素存储到单链表的结点中
p->next=copy(array+1,length-1);//结点的指针域指向下一个结点,下一个结点指针由递归函数返回
return p;
}
void traverseLinkedList(Node * element0) //遍历(不带表头结点的)单链表
{
/*
使用if(element0==NULL)也是可以的,条件下面的语句cout<<element0->data<<endl;要去掉
输出的结尾会多一个逗号
*/
if(element0->next==NULL)//使用这个条件结束递归,是为了让输出美观点
{
cout<<element0->data<<endl;
return;
}
cout<<element0->data<<",";
traverseLinkedList(element0->next);
}
2.数组转链表之二
1)将一个int[ ]型数组中的各个元素依次存储到(带表头的)单链表中
2)遍历单链表
#include<iostream>
using namespace std;
typedef struct node
{
int data;
struct node * next;
}Node,*NodePointer;
NodePointer transform(int * array,int length)
{
if(length==0) //递归的最后一层
{
Node * head=new Node;//创建表头结点
head->next=NULL;//表头结点的指针域置空,表明是个空表
return head;//在回归的过程当中,表头结点与每一层中的结点绑定关系
}
Node * p=new Node;
p->data=array[0];
Node * head=transform(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 traverseArray(int * array,int length)
{
if(length==1)
{
cout<<0[array]<<endl;
return;
}
cout<<0[array]<<",";
traverseArray(array+1,length-1);
}
int main()
{
int array[]={10,9,26,3,93,94,92,13,19};
int length=sizeof(array)/sizeof(int);
cout<<"原数组:\t";
traverseArray(array,length);
Node * head=transform(array,length);
cout<<"单链表:\t";
traverseLinkedList(head);
return 0;
}
3.链表转数组
1)创建先进先出的(不带表头结点的)单链表,单链表结点的数据为char型,其数据由键盘输入
2)遍历单链表
3)将单链表中的数据依次存储到数组中
4)遍历数组
#include<iostream>
using namespace std;
typedef struct node
{
char data;
struct node * next;
}Node,*NodePointer;
NodePointer createLinkedList() //尾插法创建(不带表头的)单链表
{
char data;
cin>>data;//由键盘输入入数据
if(data=='0')//当输入字符'0'时,递归结束
{
return NULL;
}
Node * p=(NodePointer)malloc(sizeof(Node));
p->data=data;
p->next=createLinkedList();
return p;
}
void traverseLinkedList(Node * element0)//遍历(不带表头结点的)单链表
{
if(element0==NULL)//单链表中的结点遍历结束,开始回归
{
cout<<endl;
return;
}
cout<<element0->data;//输出单链表的结点数据,
//因为结点数据是字符,所以遍历时不再使用逗号隔开数据
traverseLinkedList(element0->next);//向单链表中的下一结点运动
}
char * transform(Node * element0,int length=0)//将单链表中的结点数据存储到数组当中
{
/*
这里的length预先赋值,
在主函数调用transform函数时不用向length传递参数
用来存储数组的下标及长度
*/
if(element0==NULL)//递归的最后一层(在这里length就可以当作数组的长度使用)
{
char * array=new char[length+1];//创建字符数组
array[length]='\0';//在字符数组的末尾加上'\0'
return array;//返回字符数组的首字节指针
}
char * array=transform(element0->next,length+1);//往下传递,操作下一结点,记录结点的下标
array[length]=element0->data;//根据数组下标和结点次序,将结点数据存储到数组当中
return array;
}
void traverseArray(char * array)//遍历字符数组
{
if(*(array))//字符数组还没遍历到'\0'
{
cout<<*array;//因为操作的是字符数组,这里就不用逗号隔开字符了
traverseArray(array+1);//向函数的下一层传递后继元素的指针
}else//字符数组遍历到'\0'
{
cout<<endl;//换行
return;//结束递归
}
}
int main()
{
Node * element0=createLinkedList();//创建单链表
cout<<"遍历单链表:\t";
traverseLinkedList(element0);//遍历单链表
char * array=transform(element0);//将单链表中的结点数据存储到数组当中
cout<<"遍历数组:\t";
traverseArray(array);//遍历数组
return 0;
}
4.整数转链表
1)任意输入一个整数n(n>10且n<=123456789),将其从低位到高位依次存储到单链表中
2)遍历单链表。
例:输入:1003
存储至单链表:3->0->0->1
输出:3001
#include<iostream>
using namespace std;
typedef struct node//单链表的结点结构体
{
int data;
struct node * next;
}Node,*NodePointer;
void traverseLinkedList(Node * element0) //遍历(不带表头的)单链表
{
if(element0->next==NULL)//到达单链表的尾结点,即递归的最后一层,
{
cout<<element0->data<<endl;
return;
}
cout<<element0->data;
traverseLinkedList(element0->next);//向下一层函数传递后继结点
}
NodePointer transform(long number)//将number拆分成单个数字,从低位到高位依次存储至单链表的结点中
{
if(number>9)
{
NodePointer p=new Node;
p->data=number%10;
p->next=transform(number/10);//尾插法生成单链表
return p;
}else//递归的最后一层,number此时为最高位的数字,将其存储至单链表的尾结点
{
NodePointer p=new Node;
p->data=number;
p->next=NULL;
return p;
}
}
int main()
{
long x;
cin>>x;
while(x<10 || x>123456789) //输入的数不符合条件,继续输入
{
cout<<"输入的数应大于10且小于123456789"<<endl;
scanf("%d",&x);
}
NodePointer p=transform(x);
traverseLinkedList(p);
return 0;
}
5.逆置单链表
1)创建先进先出的(带表头的)单链表,单链表结点的数据为int型,其数据由键盘输入。
2)遍历单链表
3)逆置单链表中的结点
4)再次遍历单链表,验证逆置单链表后的结果
#include<iostream>
using namespace std;
typedef struct node//单链表的结点结构体
{
int data;
struct node * next;
}Node,*NodePointer;
NodePointer createLinkedList() //头插法创建(带表头的)单链表,这里输入的数据顺序与单链表中各结点的数据顺序保持一致
{
int data;
cin>>data;
if(data==0) //到达递归的最后一层,输入整数0时,开始回归
{
Node * head=new Node;//创建表头结点
head->next=NULL;//表头结点的指针域置空,表明这是一个空的单链表,同时为头插法在插入第一个新结点时服务
return head;//返回表头指针
}
Node * head=createLinkedList();
Node * p=new Node;
p->data=data;
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);
}
NodePointer reverseLinkedList(Node * head)//逆置(带表头的)单链表
{
Node * p=head->next;//p指向head的后继结点
if(p==NULL)//递归的最后一层,只剩下表头
{
//cout<<"List is empty now!"<<endl;
return head;
}
head->next=p->next;//而head指向p的后继结点
p->next=NULL;//p结点的指针域置空,解除关系
Node * p0=reverseLinkedList(head);
p0->next=p;//回归的时候使用尾插法,重新绑定关系
return p;
/*
思路:在递归方法的每一层,把单链表的结点关系依次解除,
关系已解除的结点由每层递归方法中的指针变量p指向,
head变量从始至终没有变化,
当head指向的表头结点的next值为NULL时,
单链表的结点关系已完全分开,开始回归
在方法回归的过程中,单链表的结点关系进行新一轮的绑定
在第一层方法中,p指向第1个结点,head指向第2个结点 p=head->next;head->next=p->next;
在第二层方法中,p指向第2个结点,head指向第3个结点 p=head->next;head->next=p->next;
在第三层方法中,p指向第3个结点,head指向第4个结点 p=head->next;head->next=p->next;
...
在第n层方法中,p指向第n个结点,head指向第n+1个结点 p=head->next;head->next=p->next;
head会比p先一步指向尾结点
在最后一层方法中,p为NULL,head指向最后一个结点 p=head->next;head->next=p->next;
*/
}
int main()
{
NodePointer head=createLinkedList();//创建(带表头的)单链表
traverseLinkedList(head);//遍历(带表头的)单链表
reverseLinkedList(head);//逆置(带表头的)单链表
traverseLinkedList(head);//遍历逆置之后的(带表头的)单链表
return 0;
}
6.计算链表的长度
1)创建先进后出的(带表头的)单链表
2)单链表结点的数据为int型,其数据由键盘输入
3)遍历单链表
4)计算单链表中的结点个数
#include<iostream>
using namespace std;
typedef struct node
{
int data;
struct node * next;
}Node,*NodePointer;
NodePointer createLinkedList0(Node * tail=NULL) //创建先进后出的(带表头的)单链表
{
int data;
cin>>data;
if(data==0)
{
Node * head=new Node;
head->next=tail;
return head;
}
Node * p=new Node;
p->data=data;
p->next=tail;
return createLinkedList0(p);
/*
从函数第一层至倒数第二层,每层创建的结点,结点指针都会向下一层传递,
由下一层创建的结点的指针域指向
在最后一层中,创建表头结点,由表头结点指针域指向倒数第二层传递过来的结点指针,即首结点指针,
返回头结点指针
设尾结点为n结点,尾结点的前驱结点为n-1结点,依此类推
第一层 第1次输入的数据 存储进n-0结点的数据域 n-0结点指针域为空
第二层 第2次输入的数据 存储进n-1结点的数据域 n-1结点指针域为n-0结点的指针
第三层 第3次输入的数据 存储进n-2结点的数据域 n-2结点指针域为n-1结点的指针
...
第k-1层 第k-1次输入的数据 存储进n-k结点的数据域 n-k结点指针域为n-k-1结点的指针
第k层(最后一层) 无数据输入,创建表头结点 表头结点指针域为n-k结点的指针
*/
}
NodePointer createLinkedList()
{
return createLinkedList0(NULL);//createLinkedList0函数的调用,要么不传参,要传参只能传NULL
}
void traverseLinkedList(Node * head)//遍历带表头的单链表
{
if(head->next->next==NULL)
{
cout<<head->next->data<<endl;
return;
}
cout<<head->next->data<<",";
traverseLinkedList(head->next);
}
int getLength(Node * head)//获取带表头的单链表长度,除去表头结点
{
static int length=0;
if(head==NULL)
{
return length-1;
}
length++;
return getLength(head->next);
}
int main()
{
NodePointer head=createLinkedList();
traverseLinkedList(head);
cout<<"length:\t"<<getLength(head)<<endl;
return 0;
}
7.求3至9位数中的水仙花数
1)由键盘输入两个整数,确定整数范围
2)输入的两个整数均大于等于100小于等于999999999
3)求出这段范围的水仙花数
3至9位的水仙花数如下:
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;
int length=0;
long long isDaffodilNumber(long long number)
{
if(number<=9)//到达递归的最后一层
{
length++;//确定了最开始的number是几位数,
long long power=1;//用来累乘number,此时的number是个个位数,是最开始的number的最高位
for(int i=0;i<length;i++)
{
power*=number;//power累乘number
}
return power;//得出number的length次方
}
length++;//通过length的累加得出最开始的number是几位数
long long power=1;
int unit=number%10;
long long part=isDaffodilNumber(number/10);
/*
调用自身,重复上面的操作,直至递归最后一层
最后一层返回 number最高位的length次方
倒数第二层返回 number次高位的length次方与number最高位的length次方之和
...
第三层返回 number百位的length次方与number若干个更高位分别length次方之和
第二层 number十位的length次方与number若干个更高位分别length次方之和
第一层 number个位的length次方与number若干个更高位分别length次方之和
*/
for(int i=0;i<length;i++)
{
power*=unit;
}
return power+part;
}
void getDaffodilNumber(int begin,int end)
{
for(int i=begin;i<=end;i++)
{
length=0;
if(isDaffodilNumber(i)==i)
{
cout<<i<<endl;
}
}
}
int main()
{
long long x,y;
cin>>x>>y;
long long difference=x-y;
difference=difference>0?difference:-difference;
x=(x+y-difference)/2;
y=x+difference;
getDaffodilNumber(x,y);
return 0;
}
改进版,为提高运行速度加缓存,为更酷加了求乘方函数
#include<iostream>
#include<cstring>
using namespace std;
long long getPower(long long x,int depth)//求x的depth次方
{
if(depth==1)
{
return x;
}
return x*getPower(x,depth-1);
}
int length=0; //用来存储number的位数,确定number是几位数,每测试一个number,length就要归零一次
long long array[11]={0};
/*
在number被拆成多个个位数时,无非是0到9之间的任意一个,而个位数与数组的下标刚好又能凑一起去,
于是乎,把个位数当成数组的下标使用
所以用数组array存储每个个位数的length次方,
第0个元素存储0的length次方
第1个元素存储1的length次方
第2个元素存储2的length次方
第3个元素存储3的length次方
第4个元素存储4的length次方
第5个元素存储5的length次方
...
第9个元素存储9的length次方
第10个元素用来存储number的位数
*/
long long isDaffodilNumber(long long number)
{
if(number>9)//number大于9,说明number仍是多位数,继续拆分
{
length++;//全局变量length,通过length的累加得出最开始的number是几位数
int x=number%10;//把number的个位数存储在当前这层函数的变量x中
long long unit=isDaffodilNumber(number/10);
/*
number除以10取整,去掉number的个位数,向下传递,重复以上操作,直到递归的最后一层
在倒数第二层函数中的变量unit的值为number最高位的length次方
在倒数第三层函数中的变量unit的值为number次高位的length次方加上number最高位的length次方
...
在第三层函数中的变量unit的值为number百位的length次方加上number前若干高位的length次方的和
在第二层函数中的变量unit的值为number十位的length次方加上number前若干高位的length次方的和
在第一层函数中的变量unit的值为number个位的length次方加上number前若干高位的length次方的和
*/
if(x==0)//若number对10取余得到的数为0,就不用再求0的length次方了,因为0的任何次方都是0
{
return unit;//直接返回回归的unit
}
if(array[x]!=0)//若与x对应的array[x]已经存储了x的length次方
{
return array[x]+unit;//直接用array[x]加上unit
}
array[x]=getPower(x,length);
//在上面两个条件不满足的情况下,求出x的length次方,存储至array[x]中
return array[x]+unit;
}else
{//递归的最后一层
length++;
//全局变量length,通过前面若干层和最后一层递归的累加,已确定number是几位数
if(array[10]!=length)
{
/*
数组第10个元素的值与length不相等,
该条件说明遇到两种情况,
一是头一次执行该语句,
二是校验的number由原来的n位数,变成n+1位数了
*/
memset(array,0,sizeof(array));//给数组清零
array[10]=length;//更新数组array第10个元素的值,
array[number]=getPower(number,length);
/*
此时number已经是个位数,并且是最开始的number的最高位
求出number的length次方,将其存储到数组array的第number个元素中
*/
return array[number];
}else
{
/*
数组第10个元素的值与length相等,
说明进校验(是否为水仙花数)一组number中,位数相同
已经是个位数的number的length次方,已经存储在array[number]中
*/
return array[number];
}
}
}
void revealDaffodilNumber(long long begin,long long end)
{
for(int i=begin;i<=end;i++)
{
length=0;//每次调用isDaffodilNumber函数前,length必须清零
if(isDaffodilNumber(i)==i)
{
cout<<i<<endl;
}
}
//原本这里也打算用递归,可是栈溢出了
/*
if(begin>end)
{
return;
}
length=0;
if(isDaffodilNumber(begin)==begin)
{
cout<<begin<<endl;
}
//cout<<"begin:\t"<<begin<<endl;
revealDaffodilNumber(begin+1,end);
*/
}
int main()
{
long long x,y;
cin>>x>>y;
long long difference=x-y;
difference=difference>0?difference:-difference;
x=(x+y-difference)/2;
y=x+difference;
revealDaffodilNumber(x,y);
return 0;
}