2020-10-31

利用栈实现的全排列

数据结构学到栈了,了解到可以将递归函数的调用看作是函数的压栈,递归函数的结束返回上一层函数可以看作函数的出栈。
之前用递归函数实现过全排列,现在用栈实现一遍。
用栈的第k层保存第k层递归函数,每一层保存平行的变量。。。

问题

假设有一个盒子box[n],里面装着n个小球ball。有个条形、有凹槽的木块per[n],第一个凹槽放一个小球,接着放下一个,放满时,就完成一个排列了。
但第一个凹槽可放的小球有n种肯,第二个凹槽有n-1种可能……最后一个凹槽有一种可能。所有可能就是n的阶乘

#include<iostream>
using namespace std;
#include<vector>

//单个元素的结构体 
struct Ball{
	char ch;//元素 
	bool flag;//flag==true 时,该元素未被选择 
};

int main(){
	vector<int> si;//该层元素从si.back()下标开始扫描box数组 
	vector<int> sc;//该层元素由sc.back()种机会 
	int n; 
	Ball* box; //存放被排列的元素数组 
	char* per;// 存放已经排列好的元素,存满时输出。 
	
	cout << "请输入全排列的元素个数n:" << endl;
	cin >> n;
	box = new Ball[n];
	per = new char[n+1]; per[n] = '\0';//字符串已'\0'结尾 
	
	cout << "请输入" << n << "个元素:" << endl;
	for(int i = 0; i < n; i++){
		cin >> box[i].ch;
		box[i].flag = true;
	}
	cout << endl;
	
	//第一层初始化 
	si.push_back(0);//该层从0开始扫描box数组 
	sc.push_back(n-si.size()+1);//该层有n个选择 
	
	while(si.size() != 0){//当递归不结束
		 
		while(si.back() < n && sc.back() > 0){//该层:box没有被扫描完,且有选择没有被选 
			if(box[si.back()].flag){//该层种:找到了没有被选择的元素 
				box[si.back()].flag = false;//该层:标记为不可选择 
				per[si.size()-1] = box[si.back()].ch;//该层:排列该可选元素 
				sc[si.size()-1]--;//该层可选择可能性减一 
				si[si.size()-1]++; //回到该层时,扫描位置为下一个 
				
				//进入到下一层 
				si.push_back(0);
				sc.push_back(n-si.size()+1);//下一层的可能性初始化由该层的层数决定。 
			}
			else{
				si[si.size()-1]++;//如果被指向的元素不可选择,那么指向下一个 
			}  
		}
		
		if(si.size()-1 == n){//如果已经排列好了所有元素则输出,并返回上一层 
			cout << per << endl;
			si.pop_back();
			sc.pop_back();
		}
		
		//循环:递归未结束,若该层没有下一个可选择元素,恢复已选元素,并返回上一层 
		while(si.size() && sc.back() == 0){
			box[si.back()-1].flag = true;
			si.pop_back();
			sc.pop_back();
		}
		
		//当递归未结束,且该层仍有可选元素时:恢复已选元素。为下一层选择准备。 
		if(si.size()){
			box[si.back()-1].flag = true;
		}
	}
	
	delete[] per;
	delete[] box;
	return 0;
}

运行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值