算法设计与分析课程记录week2

算法设计与分析课程记录week2

PS:此文章仅作为个人课程期间的学习记录

递归算法设计技术

1. 递归的概念

在定义一个过程或函数时出现调用本过程或本函数的成分,称之为递归。若调用自身,称之为直接递归。若过程或函数p调用过程或函数q,而q又调用p,称之为间接递归

能够用递归解决问题的三个条件:

  • 需要解决的问题可以转化为一个或多个子问题来求解,而这些子问题的求解方法与原问题完全相同,只是在数量规模上不同。
  • 递归调用的次数必须是有限的。
  • 必须有出口来结束递归的条件来终止递归。

何时使用递归?

  1. 定义是递归的
    如:求n!和Fibonacci数列等
  2. 数据结构是递归的
    如:单链表,二叉树等
  3. 问题的求解方法是递归的
    如:汉诺塔问题

不建议在太大的数据量使用递归的原因
递归调用是函数嵌套调用的一种特殊情况,由于每次调用时,它的参量和局部变量均不相同,因而得保证了各个复制件执行时的独立性。故系统为每一次调用开辟一组存储单元,用来存放本次调用的返回地址以及被中断的函数的参量值。
这些单元以系统栈的形式存放,每调用一次进栈一次,当返回时执行出栈操作,把当前栈顶保留的值送回相应的参量中进行恢复,并按栈顶中的返回地址,从断点继续执行。具体看下图例子。
在这里插入图片描述
在这里插入图片描述
从以上过程可以得知:

  • 每递归调用一次,就需进栈一次,最多的进栈元素个数称为递归深度,当n越大,递归深度越深,开辟的栈空间也越大
  • 每当遇到递归出口或完成本次执行时,需退栈一次,并恢复参量值,当全部执行完毕时,栈应为空。

2.递归算法设计

数学归纳法是一种论证方法,而递归是算法和程序设计的一种实现技术,数学归纳法是递归的基础。
第一与第二数学归纳法:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
递归算法设计的一般步骤
在这里插入图片描述
在这里插入图片描述
递归数据结构的定义:
采用递归方式定义的数据结构称为递归数据结构。在递归数据结构定义中包含的递归运算称为基本递归运算

单链表的递归算法设计
在这里插入图片描述在这里插入图片描述
二叉树的递归算法设计
在这里插入图片描述在这里插入图片描述

3. 递归算法设计实例

求解n皇后问题
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

4.递归算法转化非递归算法

把递归算法转化为非递归算法有如下两种基本方法:

  1. 直接用循环结构的算法替代递归算法。
  2. 用栈模拟系统的运行过程,通过分析只保存必须保存的信息,从而用非递归算法替代递归算法。

第一种是直接转化法,不需要使用栈。第二种是间接转化法,需要使用栈。

5.课堂练习

1.利用已给函数练习创建输出删除和复制一棵二叉树,还有求根节点到任意节点的正向与逆向路径。

我所构造的二叉树示意图如下:
在这里插入图片描述
代码如下:

//二叉树的基本运算算法+例2.8到例2.11
#include <malloc.h>
#include <stack>
#include <vector>
#include <string>
#include<iostream>
using namespace std;
typedef int ElemType;
typedef struct node 
{	ElemType data;				//数据元素
	struct node *lchild;		//指向左孩子结点
	struct node *rchild;		//指向右孩子结点
} BTNode;						//二叉链结点类型

BTNode *CreateBTree(ElemType a[],ElemType b[],int n)	//对应例2.8的算法
//由先序序列a[0..n-1]和中序序列b[0..n-1]建立二叉链
{
	int k;
	if (n<=0) return NULL;
	ElemType root=a[0];			//根结点值
	BTNode *bt=(BTNode *)malloc(sizeof(BTNode));
	bt->data=root;
	for (k=0;k<n;k++)			//在b中查找b[k]=root的根结点
		if (b[k]==root)
			break;
	bt->lchild=CreateBTree(a+1,b,k);			//递归创建左子树
	bt->rchild=CreateBTree(a+k+1,b+k+1,n-k-1);	//递归创建右子树
	return bt;
}
void DispBTree(BTNode *bt)				//采用括号表示输出二叉链bt
{
	if (bt!=NULL)
	{	printf("%c",bt->data);//修改data域为字符型
		if (bt->lchild!=NULL || bt->rchild!=NULL)
		{	printf("(");						//有孩子结点时才输出(
			DispBTree(bt->lchild);				//递归处理左子树
			if (bt->rchild!=NULL) printf(",");	//有右孩子结点时才输出,
			DispBTree(bt->rchild);				//递归处理右子树
			printf(")");						//有孩子结点时才输出)
		}
	}
}
void DestroyBTree(BTNode *&bt)		//对应例2.9的算法
//释放以bt为根结点的二叉树
{	if (bt!=NULL)
	{	DestroyBTree(bt->lchild);
		DestroyBTree(bt->rchild);
		free(bt);
	}
}
void CopyBTree(BTNode *bt,BTNode *&bt1)	//对应例2.10的算法
//由二叉树bt复制产生bt1
{
	if (bt==NULL)
		bt1=NULL;
	else
	{
		bt1=(BTNode *)malloc(sizeof(BTNode));
		bt1->data=bt->data;
		CopyBTree(bt->lchild,bt1->lchild);
		CopyBTree(bt->rchild,bt1->rchild);
	}
}
bool Findxpath1(BTNode *bt,int x,vector<int> &path)			//对应例2.11的解法1
//求根结点到x结点的(逆向)路径
{
	if (bt==NULL)					//空树返回false
		return false;
	if (bt->data==x)				//找到值为x的结点
	{
		path.push_back(x);			//结点值加入path中,并返回true
		return true;
	}
	else if (Findxpath1(bt->lchild,x,path) || Findxpath1(bt->rchild,x,path))
	{
		path.push_back(bt->data);	//结点值加入path中,并返回true
		return true;
	}
}
bool Findxpath2(BTNode *bt,int x,vector<int> tmppath,vector<int> &path)	//对应例2.11的解法2
//求根结点到x结点的(正向)路径
{
	if (bt==NULL)							//空树返回false
		return false;
	tmppath.push_back(bt->data);			//当前结点加入path
	if (bt->data==x)						//当前结点值为x,返回true
	{
		path=tmppath;
		return true;
	}
	bool find=Findxpath2(bt->lchild,x,tmppath,path);//在左子树中查找
	if (find)								//左子树中成功找到
		return true;
	else									//左子树中没有找到,在右子树中查找
		return Findxpath2(bt->rchild,x,tmppath,path);
}
int main()
{
	
	int a[]={'A','B','D','C','E'};
	int b[]={'D','B','A','C','E'};
 	BTNode *bt = CreateBTree(a,b,5);
 	BTNode *bt1;
 	//输出创建的树bt
	printf("创建的树bt:");
	DispBTree(bt);
	printf("\n");
	CopyBTree(bt,bt1);//复制bt到bt1
	
	DestroyBTree(bt);//销毁创树bt
	
	//输出复制的树bt1
	printf("复制的树bt1:");
	DispBTree(bt1);
	printf("\n");
	
	//创建两个迭代器 
	vector<int> v;
	vector<int> v1;

	//逆向输出路径	
	Findxpath1(bt1,'D',v);
	vector<int>::iterator it = v.begin();
	cout<<"根节点A到D的逆向输出路径:";
	for (; it != v.end(); it++){	
		printf("%c ",*it);
	}
	cout<<endl;
	//正向输出路径
	Findxpath2(bt1,'D',v1,v);
	vector<int>::iterator it1 = v.begin();
	cout<<"根节点A到D的正向输出路径:";
	for (; it1 != v.end(); it1++){
		printf("%c ",*it1);
	}
	return 0;
}

输出结果:
在这里插入图片描述

2.leetcode两道题

21. 合并两个有序链表
234. 回文链表

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值