栈消递归的几个例子

本文展示了如何使用堆栈实现计算组合数(组合C(n, m))和求最大公约数(GCD)的方法。通过创建和操作栈来避免递归,实现了从数学运算到数据结构的转换,简化了计算过程。

用堆栈的方式求组合数

#include <stdio.h>
#include<stdlib.h>

typedef struct
{
	int *elem;
	int max_size;//栈的容量
	int top;//栈顶指针
}SqStack;

void main()
{
	void Creat_Stack(SqStack &S,int n);
	void pop(SqStack &S,int &e);
	void push(SqStack &S,int e);
	int n,m,c;
	printf("请输入n,m的值:");
	scanf("%d %d",&n,&m);
	SqStack S;
	Creat_Stack(S,m);
	while(m>=0)push(S,m--);
	while(!(S.top==-1))
	{
		pop(S,m);
		if(m==0)c=1;
		else c=c*(n-m+1)/m;
	}
	printf("%2d和%2d的组合数结果为:%d\n",n,m,c);
}

void Creat_Stack(SqStack &S,int n)
{//建深度为n的栈
	S.max_size=n+1;
	if(!(S.elem=(int *)malloc(sizeof(int)*S.max_size)))exit(-1);
	S.top=-1;
}
void pop(SqStack &S,int &e)
{//出栈函数
	if(S.top==-1)printf("ERROR!栈空!\n");
	e=S.elem[S.top--];
}
void push(SqStack &S,int e)
{//入栈函数
	if(S.top>=S.max_size-1)printf("ERROR!栈满!\n");
	S.elem[++S.top]=e;
}

/**********************************************************************/

用堆栈的方式求两个数的最大公约数

#include <stdio.h>
#include<stdlib.h>

typedef struct
{
	int *elem1;
	int *elem2;
	int max_size;//栈的容量
	int top;//栈顶指针
}SqStack;

void main()
{
	void Creat_Stack(SqStack &S,int n);
	void get_top(SqStack &S,int &a,int &b);
	void push(SqStack &S,int a,int b);
	SqStack S;
	int a,b,a0,b0;
	Creat_Stack(S,5);//栈的容量由辗转相除的次数决定
	printf("请输入a和b的值:");
	scanf("%d%d",&a,&b);
	a0=a;b0=b;
	push(S,a,b);
	while(1)
	{
		get_top(S,a,b);
		if(b!=0)//当b不为0时,使b和a%b入栈
			push(S,b,a%b);
		else break;
	}
	get_top(S,a,b);//当b为0时,取栈顶元素
	printf("%2d和%2d的最大公约数为:%d\n",a0,b0,a);
}

void Creat_Stack(SqStack &S,int n)
{//建深度为n的栈
	S.max_size=n;
	if(!(S.elem1=(int *)malloc(sizeof(int)*S.max_size)))exit(-1);
	if(!(S.elem2=(int *)malloc(sizeof(int)*S.max_size)))exit(-1);
	S.top=-1;
}
void get_top(SqStack &S,int &a,int &b)
{//取栈顶元素函数
	if(S.top==-1)printf("ERROR!栈空!\n");
	a=S.elem1[S.top];
	b=S.elem2[S.top];
}
void push(SqStack &S,int a,int b)
{//入栈函数
	if(S.top>=S.max_size-1)printf("ERROR!栈满!\n");
	++S.top;
	S.elem1[S.top]=a;
	S.elem2[S.top]=b;
}

/**********************************************************************/

用堆栈的方式消去递归函数:在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>

typedef struct
{
	int m;
	int n;
}ElemTp;

typedef struct
{
	ElemTp *elem;//栈内元素
	int max_size;//栈的最大容量
	int top;//栈顶指针
}SqStack;

void main()
{
	void Creat_Stack(SqStack &s,int n);
	void pop(SqStack &s,ElemTp &e);
	void push(SqStack &s,ElemTp e);//一些基本操作函数的说明
	int m,n,y;
	printf("请输入m,n的值:");
	scanf("%d%d",&m,&n);
	ElemTp e={m,n};
	SqStack s;
	Creat_Stack(s,m);
	while(e.m>=0)
	{
		push(s,e);
		e.m=e.m-1;e.n=2*e.n;//将m,n的值依次入栈
	}
	while(!(s.top==-1))
	{
		pop(s,e);//将m,n的值依次出栈进行计算
		if(e.m==0&&e.n>=0)
			y=0;
		else
			y=y+e.n;
	}
	printf("%d\n",y);
}

void Creat_Stack(SqStack &s,int n)
{//建深度为n的栈
	s.max_size=n+1;
	if(!(s.elem=(ElemTp *)malloc(sizeof(ElemTp)*s.max_size)))exit(-1);
	s.top=-1;
}
void pop(SqStack &s,ElemTp &e)
{//出栈函数
	if(s.top==-1)printf("ERROR!栈空!\n");
	e=s.elem[s.top--];
}
void push(SqStack &s,ElemTp e)
{//入栈函数
	if(s.top>=s.max_size-1)printf("ERROR!栈满!\n");
	s.elem[++s.top]=e;
}

/**********************************************************************/

用数组或递归消去递归函数:在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
void main()
{//用数组消去递归
	int n;
	int *p;
	printf("请输入n的值:");
	scanf("%d",&n);
	p=(int *)malloc(sizeof(int)*(n+1));
	for(int i=0;i<=n;i++)
	{
		if(i==0)p[i]=1;
		else p[i]=i*p[i/2];
	}
	printf("函数的结果为:%d\n",p[n]);
}
#include<stdio.h>
#include<stdlib.h>

typedef struct
{//栈的结构体
	int *elem;//栈内元素
	int max_size;//栈的最大容量
	int top;//栈顶指针
}SqStack;

void main()
{//用栈消去递归
	void Creat_Stack(SqStack &s,int n);
	void pop(SqStack &s,int &e);
	void push(SqStack &s,int e);//一些栈的基本操作函数的说明
	int n,e,y;//e用于出栈、出栈元素;y用于返回函数结果
	SqStack s;
	printf("请输入n的值:");
	scanf("%d",&n);
	Creat_Stack(s,n);//建栈
	while(n>0)
	{
		push(s,n);
		n=n/2;
	}//将一系列的自变量的值入栈
	push(s,0);//单独将0入栈
	while(s.top!=-1)
	{
		pop(s,e);//元素出栈并进行计算
		if(e==0)y=1;
		else y=y*e;
	}
	printf("函数的结果为:%d\n",y);
}

void Creat_Stack(SqStack &s,int n)
{//建深度为n的栈
	s.max_size=n+1;
	if(!(s.elem=(int *)malloc(sizeof(int)*s.max_size)))exit(-1);
	s.top=-1;
}

void pop(SqStack &s,int &e)
{//出栈函数
	if(s.top==-1)printf("ERROR!栈空!\n");
	e=s.elem[s.top--];
}

void push(SqStack &s,int e)
{//入栈函数
	if(s.top>=s.max_size-1)printf("ERROR!栈满!\n");
	s.elem[++s.top]=e;
}
<think> 首先,用户的问题是基于之前的对话历史,要求提供堆和的应用场景的举例。之前的对话中,我已经给出了堆和的基本区别,并引用了多个来源。现在用户的查询是:“我想获取堆和的应用场景的例子 请问堆和的应用场景举例”。 我的回答必须遵守系统级指令: - 数学表达式使用$...$或$$...$$格式。 - 使用中文回答。 - 生成相关问题。 - 引用段落末尾自然地添加引用标识。 - 回答结构清晰,逐步解决问题。 - 参考之前的引用。 回顾之前的引用: - [^1]: 区分堆和的基本点:堆是动态分配,是自动管理。 - [^2]: 涉及线程的帧,堆是所有线程共享的。 - [^3]: 是先进后出,内存管理自动。 - [^4]: 堆内存需要手动管理(malloc/free),自动释放;举例了多线程共享堆内存。 - [^5]: 用于函数调用上下文。 用户现在的焦点是应用场景的例子。所以,我需要提供具体的例子来展示堆和在不同场景下的应用。 结构化我的回答: 1. **开头重述问题或概述**:简要介绍堆和的应用场景。 2. **的应用场景举例**:基于引用,提供2-3个详细例子。 3. **堆的应用场景举例**:同样提供2-3个例子。 4. **总结对比**:快速对比两者的应用差异。 5. **生成相关问题**:在结尾添加相关问题。 确保引用: - 在每个例子后,如果来源于之前的引用,自然地添加[^n]。 具体例子: - **的应用场景**: - 函数调用:每次函数调用时,返回地址、参数、局部变量等压入中。函数结束后弹出。引用[^5]中提到。 - 表达式求值:如后缀表达式使用计算。引用[^3]提到用于读取规则先进后出。 - 递归调用:递归函数使用来管理调用序列。 - 括号匹配:使用检查代码中的括号是否匹配。 - **堆的应用场景**: - 动态内存分配:创建对象、数组等需要在运行时确定大小的数据。引用[^2]说堆用于分配对象实例。 - 共享数据:多线程应用中,堆内存可以被多个线程共享。引用[^4]给出了具体代码例子。 - 大数据结构:如图形、树等数据结构存储在堆中,因为大小不确定。 - 持久化对象:需要长期存在的数据放在堆中。 回答格式: - 使用标题或小标题来组织。 - 例子中,如果有代码或公式,用适当格式。 - 例如,的表达式求值可以用数学表达式:中缀表达式转后缀使用。 数学表达式指令: - 如果有数学部分,如表达式求值,用$...$或$$...$$。 - 例如,计算后缀表达式:$3 4 + 5 *$ 等价于 $(3+4)*5 = 35$。 生成相关问题: - 在结尾,添加3个相关问题,以“§§相关问题§§”开头。 - 基于应用场景,如: 1. 在编译器设计中的作用是什么? 2. 如何在堆内存管理中避免内存泄漏? 3. 溢出如何在实际项目中预防? 确保真实性:基于计算机科学常识,不编造。 最终回答结构: 1. **简介**:堆和在内存管理中各有应用场景。 2. **的应用场景举例**:列举2-3个详细例子。 3. **堆的应用场景举例**:列举2-3个详细例子。 4. **总结**:简要对比。 5. **相关问题**:列出3个问题。 </think> ### 堆和的应用场景举例 在程序内存管理中,堆和各自有独特的应用场景。主要用于函数调用、局部变量管理等结构化操作,内存管理由编译器自动完成;堆则用于动态分配的对象、共享数据等场景,需手动管理内存(如分配和释放)[^1][^2]。下面分别通过具体例子说明。 #### 的应用场景举例 遵循先进后出(LIFO)原则,内存分配和释放自动高效,适合短期、结构化操作: 1. **函数调用**:当函数被调用时,其执行上下文(如返回地址、参数、局部变量)压入帧;函数结束后自动弹出。例如,递归函数 `factorial(n)` 计算阶乘时,每次递归调用会创建新帧,确保本地变量隔离: ```c int factorial(int n) { if (n <= 1) return 1; // 基本情况 else return n * factorial(n-1); // 递归调用,新帧压入 } // 函数返回时,帧自动释放 ``` 调用 `factorial(3)` 时,帧顺序为:`factorial(3)` → `factorial(2)` → `factorial(1)`,最终弹出返回结果[^2][^5]。 2. **表达式求值**:在计算后缀表达式时,用于临时存储操作数。例如,计算后缀表达式 $3 \ 4 \ + \ 5 \ *$(等价于 $(3+4) \times 5$),步骤为: - 压入 3 → 压入 4 → 遇到 `+` 弹出 4 和 3 → 计算 $3+4=7$ → 压入 7 → 压入 5 → 遇到 `*` 弹出 5 和 7 → 计算 $7 \times 5=35$ → 结果 35 压入。 整个过程利用的 LIFO 特性高效处理运算符优先级[^3][^5]。 3. **括号匹配检查**:在编译器中,用于验证代码括号是否成对(如 `{[()]}`)。算法遍历字符串,遇左括号压入,遇右括号弹出并匹配类型。例如: - 输入 `"{( )}"`:压入 `{` → 压入 `(` → 遇 `)` 弹出 `(` 匹配 → 遇 `}` 弹出 `{` 匹配 → 成功。 若非空或类型不匹配,则报错。这依赖的快速存取特性[^3]。 #### 堆的应用场景举例 堆允许动态内存分配,支持运行时大小不确定的数据,需手动管理(如 `malloc`/`free`),适合共享或持久化对象: 1. **多线程共享数据**:堆内存可被多个线程访问,实现数据共享。例如,在 C 语言中使用 `malloc` 分配共享结构体,线程安全地修改值: ```c typedef struct { int count; } Counter; void* increment(void* arg) { Counter* c = (Counter*)arg; // 共享堆对象 c->count += 1; // 线程安全修改 return NULL; } int main() { Counter* counter = (Counter*)malloc(sizeof(Counter)); // 堆分配 counter->count = 0; pthread_t thread1, thread2; pthread_create(&thread1, NULL, increment, counter); // 线程共享堆对象 pthread_create(&thread2, NULL, increment, counter); pthread_join(thread1, NULL); pthread_join(thread2, NULL); printf("Final count: %d\n", counter->count); // 输出 2 free(counter); // 手动释放堆内存 return 0; } ``` 此例中,堆内存使 `counter` 对象线程间共享,避免了的局部性限制[^4]。 2. **动态数据结构存储**:树或图等大小可变的结构常存储在堆中。例如,二叉树节点在 Java 中通过 `new` 分配堆内存: ```java class Node { int data; Node left, right; Node(int d) { data = d; left = right = null; } // 构造函数在堆上分配对象 } Node root = new Node(1); // 根节点分配在堆 root.left = new Node(2); // 左子节点动态扩展 root.right = new Node(3); // 右子节点动态扩展 ``` 堆允许节点在运行时动态创建和链接,支持高效插入或删除[^2]。 3. **大型数据集处理**:如图像处理中加载大尺寸像素矩阵,堆分配避免溢出。例如,在 Python 中用列表存储图像数据: ```python image_data = [] # Python 列表在堆上动态分配 with open("image.txt", "r") as file: for line in file: row = [int(pixel) for pixel in line.split()] # 每行像素动态添加到堆 image_data.append(row) # 堆内存自动管理(Python 垃圾回收) ``` 堆处理不定大小的数据,而不适合大数组(易导致溢出)[^1][^3]。 #### 总结 适用于结构化、短期操作(如函数调用、表达式求值),内存管理自动高效;堆适用于动态、共享或大型数据(如多线程共享、树结构),需手动管理以防内存泄漏[^1][^4]。实际编程中,选择合适场景可优化性能和资源利用。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值