单链表 循环遍历和递归遍历 以及循 环求结点个数和递归求结点个数 的思考

本文探讨了如何将循环转换为递归,以访问链表和计算节点数。通过实例展示了无返回值和有返回值递归的实现,强调了递归中出口条件和返回值的重要性。递归执行顺序是从下到上,不同于循环的从上到下,这在处理返回值时需特别注意。递归理解和应用是理解复杂算法的关键,尤其在二叉树等数据结构中。
摘要由CSDN通过智能技术生成

我前面有很多文章一直说,递归和循环是一样的,可以相互转换。

循环是一直重复某个语句,递归是一直调用自己。要想转化,递归就得好好想想自己的内部代码和循环执行的那句代码的关系(应当一样)。

1.打印单链表
非递归

void printLnode (l* p){
	while(p){
		print(p);
		p = p->next;
	}
}

递归

void printLnode (l* p){
	print(p);
	printLnode (p->next);
}

内容上,打印的代码不变,循环移动的代码,变成了递归。
这里打印语句一定要理解为函数的功能,这样写复杂的递归时才能又快有准。
打印当前;
打印下一个;
我们发现一个问题,这个函数一直调用自己,没有退出的情况,不符合实际呀,所以,递归之后,加上一个出口就好了,递归的套路就是这样了。

void printLnode (l* p){
	if(p){
		print(p);
		printLnode (p->next);
		}
	else return;
}
//或者
void printLnode (l* p){
	if(!p){
		return;
		}
	else {
		print(p);
		printLnode (p->next);
	}
}

我们这就完成了访问。
上面有个模糊的点,因为函数的返回值是void,所以,我们就没提到返回值这个玩意。
在while循环中,我们很清楚的知道,当p为空时,函数会执行到底,函数结束,就是所有的东西结束了,在递归当中呢?

如果把递归理解为功能,那么,要是p为空就不执行该功能,不为空则打印,并,准备下一次打印。然后再从尾到头一个个结束所有函数,直到回到第一个函数(即使所有函数执行完就是结束)。

那我们要计算结点个数呢?
2.计算结点个数
非递归

int count = 0
int printLnode (l* p){
	while(p){
		count = count + 1;   //print(p);
		p = p->next;
	}
	return count;
}

递归

int count = 0
int countLnode (l* p){
	if(!p) {
		return 0;
	}else{
		//count = count + 1;   //print(p);
		return countLnode (p->next) + 1;
	}
}

这里有一个非常大的不同点,就是返回值。

循环和递归的主要区别,循环是从上到下执行,执行结束一个返回,而递归?从上到下执行,执行完之后,从下到上依次返回。也就是,最后返回值一定的第一次进入的函数,那么这时候,想把最后的(最里面的函数)返回值带出来,怎么办?

就得在return语句上下功夫了。已知:return是一个函数最后的返回值,在递归当中,一定的最里面的函数先return,最后才是第一个函数return,统计节点的时候,相当于从最后一个开始回归,0,1,2,3…等回到第一个的时候就是个数了。
所以countLnode (p->next) + 1是写在return语句中的

这种写法是根据递归的运行过程来的,没有用到count计数器,如果从代码角度来看,用count计数器该如何实现呢?
递归

int count = 0
int countLnode (l* p){
	if(!p) {
		return 0;
	}else{
		count = countLnode (p->next) + 1;
		return count;
	}
}

这里有没有发现盲点,计数器的作用不是原来的count+1了,如果写成原来的,那么他的值是不会变的,只有和上一次的变化有关,才能统计出个数,递归的统计就是从后向前的统计,count = countLnode (p->next) + 1代码依旧是从后向前统计的。


本文重点分析了:

  1. 循环和递归的转换
  2. 无返回值的递归和有返回值的递归
  3. 有返回值的递归直接返回和有返回值的递归间接返回

下一篇分析二叉树的思考。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您解答有关此问题的内容。 以下是C语言递归方式创建带头节点的单链表的代码: ``` #include <stdio.h> #include <stdlib.h> // 定义链表结构体 typedef struct Node{ int data; //数据域 struct Node *next; //指针域 }Node; // 初始化带头节点的单链表 Node* initList(){ Node *head = (Node*)malloc(sizeof(Node)); //创建头结点 head->next = NULL; //指向空指针,初始为空链表 return head; } // 递归方式插入链表结点 void insert(Node *node, int data){ if(node->next == NULL){ //如果链表为空,则新建一个结点 Node *newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; newNode->next = NULL; node->next = newNode; } else{ //递归调用插入函数,寻找下一个空结点进行插入 insert(node->next, data); } } // 遍历链表并输出结点数据 void traverse(Node *node){ if(node->next == NULL) //如果链表为空,则直接退出 return; else{ printf("%d ", node->next->data); //输出结点数据 traverse(node->next); //递归调用遍历函数,寻找下一个结点 } } // 删除链表中指定数值x的结点 void delete(Node *node, int x){ if(node->next == NULL) //如果链表为空,则退出 return; else{ //如果下一个结点数值等于x,则删除下一个结点,并将当前结点指向下一个结点的下一个结点 if(node->next->data == x){ Node *tmp = node->next; node->next = node->next->next; free(tmp); delete(node, x); //继续递归删除下一个结点 } else delete(node->next, x); //下一个结点数据不为x,则继续递归删除下一个结点 } } // 获得链表结点个数 int count(Node *node){ if(node->next == NULL) //如果链表为空,则返回0 return 0; else{ return 1 + count(node->next); //递归调用count函数,返回下一个结点结点数加1 } } // 获得链表中的最大整数 int getMax(Node *node){ int max; if(node->next == NULL) //如果链表为空,则返回0 return 0; else{ max = node->next->data; while(node->next != NULL){ if(node->next->data > max) max = node->next->data; node = node->next; } } return max; } // 获得链表中整数的平均值 double getAvg(Node *node){ int sum = 0; int num = 0; double avg; if(node->next == NULL) //如果链表为空,则返回0 return 0; else{ while(node->next != NULL){ sum += node->next->data; node = node->next; num++; } avg = (double)sum / num; } return avg; } int main(){ int i; Node *head = initList(); //初始化带头节点的单链表 //使用递归方式插入链表结点 for(i = 1; i <= 10; i++){ insert(head, i); } printf("链表结点数据为:"); traverse(head); //遍历链表并输出结点数据 printf("\n"); printf("链表结点个数为:%d\n", count(head)); //获得链表结点个数 printf("链表中的最大整数为:%d\n", getMax(head)); //获得链表中的最大整数 printf("链表中整数的平均值为:%f\n", getAvg(head)); //获得链表中整数的平均值 delete(head, 8); //删除链表中值为8的结点 printf("删除值为8的结点后的链表结点数据为:"); traverse(head); //遍历链表并输出结点数据 printf("\n"); return 0; } ``` 如果您有其他问题,请随时提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值