前几天做题的时候,发现《数据结构高分笔记》第一章有这样一个思考题,对理解递归调用帮助很大,题目如下:
题目:逆序输出单链表的数据域,要求 指针l指向链表首元结点,且只用l一个指针
(一)分析:在单链表的情况下,要逆序输出结点数据只用一个指针,除了用递归调用,好象没有别的方法了。关键在于,如何设计递归调用?
递归调用属于分治法的一种思想,一个包含直接或者间接调用自身函数的语句的函数被称为递归函数,但不是所有的调用自身都是递归,必须满足以下条件:
(1)在每一次调用自身时,必须是(在某种意义上)更接近于解;
(2)必须有一个终止 处理或者计算 的准则;
设计的算法如下:
————————————————————————————————————
void reversePrint(LNode *l) //逆序输出链表
{
if (l->next!= NULL){
reversePrint(l->next);
}
cout << l->data<<" -- ";
}
————————————————————————————————————
我们假设从首元结点到尾元结点共有9个结点,指针l指向首元结点,当执行到if语句时,很明显” l->next!= NULL “成立,于是执行“ reversePrint(l->next); ”进入递归第二层,第二层循环执行到if语句后同样” l->next!= NULL “成立,于是进入到递归第三层……值得说明的是“ reversePrint(l->next); ”语句中,( )中必须写成”( l->next )“,如果写成(l),便会进入死循环,违背了上面条件(1)。而” l->next!= NULL “就是终止处理的准则,也就是上面的条件(2);
当进入递归第九层以后,” l->next!= NULL “不成立,于是直接执行" cout << l->data<<" -- "; "输出结点9的数据,第九层递归执行结束。但第九层递归执行结束以后,第八层递归if语句执行完毕,也进入" cout << l->data<<" -- "; "语句输出结点9的数据域,第八层递归执行结束。以此类推,7、6、5、4、3、2、1依次执行" cout << l->data<<" -- "; "语句,于是整个链表就被逆序输出,而且从头到尾l指针所指的始终是首元结点(每一层的l可以看成每一层自己定义的指针,只不过名字相同,这点很重要)。因此,使用指针l,如果用for循环输出则为正序,使用递归就可以达到逆序输出的目的。
另外值得一提的是" cout << l->data<<" -- "; "语句的位置因该放在函数哪里,也是一个值得深思的问题。
(二)关于递归调用的时间复杂度问题
如上九个结点,九层循环的时间复杂度为9,也就是说这个算法时间复杂度为O(n)。初学者可能会怀疑时间复杂度为n次方,但是仔细比较就会发现,递归和循环的时间复杂度很类似。递归九层逆序输出,时间复杂度为9;for(i=1;i<=9;i++){……}循环顺序输出9次,时间复杂度也是9。
因此,灵活的使用递归和循环,可以解决线性表的各种顺序以及逆序问题!
完整的代码如下(VS2013编译环境):
————————————————————————————————————
// 逆序打印单链表的数据 指针l指向链表开始 要求只用l一个指针
/*
分析: 采用递归 printNode {if(l->next!=NULL)printNode(l->next);cout<<l->data;}
很神奇的想法!对理解递归有很大帮助!!!
*/
#include "stdafx.h"
#include <iostream>
#include "stdlib.h"
using namespace std;
static int length = 9;
typedef struct LNode{ //结点的定义
int data;
struct LNode *next;
}LNode;
LNode *createLink( )//创立链表
{
//创立头结点
LNode *head;
head = (LNode *)malloc(sizeof(LNode));
head->data = 0; head->next = NULL;
//创立剩下的结点
LNode *newNode, *p = head;
for (int i = 1; i <= length; i++) {
newNode = (LNode *)malloc(sizeof(LNode));
newNode->data = i; newNode->next = NULL;
p->next = newNode;
p = p->next;
}
return head;
}
void printLink(LNode *head)//输出链表
{
cout << "当前链表为:";
LNode *temp = head->next;
do{
cout << temp->data << " -- ";
temp = temp->next;
} while (temp->next!=NULL);
cout << temp->data;
cout << endl;
}
void reversePrint(LNode *l) //逆序输出链表
{
if (l->next!= NULL){
reversePrint(l->next);
}
cout << l->data<<" -- ";
}
int _tmain(int argc, _TCHAR* argv[])
{
LNode *head = createLink();
printLink(head);
cout << "逆序链表为:";
reversePrint(head->next);
cout << endl;
return 0;
}
————————————————————————————————————
输出结果如下:
339



被折叠的 条评论
为什么被折叠?



