`
zxxapple
  • 浏览: 79573 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

n-皇后以及全排列的问题--递归以及非递归的解法

 
阅读更多

首先说下全排序的问题  这个问题可以说是最经典的问题,

 

实现这个问题的最经典的方法莫过于递归实现了:

 

代码确实很简洁:(从网上转载---很多的)

void perm(char *buf,int start,int end)
 {   
        if(start==end){//当只要求对数组中一个字母进行全排列时,只要就按该数组输出即可    
            for(int i=0;i<=end;i++){   
                printf("%c",buf[i]);   
            }   
            printf("\n");      
        }   
        else{//多个字母全排列    
            for(int i=start;i<=end;i++){   
                char temp=buf[start];//交换数组第一个元素与后续的元素    
                buf[start]=buf[i];   
                buf[i]=temp;   
                   
                perm(buf,start+1,end);//后续元素递归全排列    
                   
                temp=buf[start];//将交换后的数组还原    
                buf[start]=buf[i];   
                buf[i]=temp;   
            }   
        }   
    }   

 简介带来的问题就是递归算法本身就不是很容易理解,另外一方面就是递归算法比较浪费内存空间。

 

  首先就是perm(buf【】,start,end)实现数组的start的索引到end索引的全排序,每次我们需要从第一个元素与需要全排的索引的第一个交换,求解完后在替换回来。。。如此递归下去,只能说到这里了,再说下去我也很迷糊

这种递归算法也有缺点,就是它不能取出中间重复的序列,加入求1,2,2,3的全排列不能取出重复的  需要另外的便利控制。。。

 

在网上看到一些全排序比较新颖的实现方法---字典序列的方法来就全排序

比如求3,1,2,4的全排列,

这种方法将这些序列进行了一个排序,比如得到全排序之后的的所有序列第一个序列是,1,2,3,4 最后一个序列是4,3,2,1

也就是递增的方法来查找序列,比如,3214的下一个序列就是3241

 

问题的关键就是如何调整这个数的 序列

方法如下:

1. 首先对要求全排序的数列进行递增的排序,

2.从序列的最后端点开始查找这样的一个元素,这个元素比相邻的后面的元素小,记录下这个元素的下标i;

3.然后此时i后方的元素是整体递减的,所以我们直接从序列的最后方开始找比元素大的元素,并记录下标j;

4,然后swap(A[i],A[j]);

5,将元素i后方的所有元素逆转;

6.然后输出,新的序列

7.知道序列全部递减停止;

 

void swap(int *a,int *b) //交换
{
	int tmp=*a;
	*a=*b;
	*b=tmp;
}

void revArr(int *arr,int k,int m) //数组arr 从k到m进行逆置
{
	while(k<m)
	{
		swap(arr+k,arr+m);
		k++;
		m--;
	}
}

void print(int *x,int n)   //打印
{
		for(int i=0;i<n;i++)
				{
 	               printf("%d ",x[i]);
				}
				printf("\n"); 
}

int fullArr(int *arr,int n)
{
	if(n==1)
	{
		return 1;
	}
	int i,j;
	while(1)
	{
        print(arr,n);

		for(i=n-2;i>=0;i--)       
		{
			if(arr[i]<arr[i+1])  //从数组后方找到后一个数大于前一个数  记住下表i
			{
				break;
			}
			if(i==0)
			{
				return 1;//函数结束出口
			}
		}

		for(j=n-1;j>i;j--)   //在i后方找到一个数比i大而且最接近i的数,我们可以直接从后先前找,因为i后方的数都是升序的
		{
			if(arr[j]>arr[i])
			{
				break;
			}
		}
		swap(arr+i,arr+j);    //交换i与j
        revArr(arr,i+1,n-1);   //i后方的数逆置
	}
}

 

说到递归 不得不让人想起n-皇后问题。

 

问题描述,就是在一个n*n的棋盘上防止n个棋子,其中任何两个棋子不可以在同行,同列,同一斜线上出现。

 

解决这个问题的最经典思路就是回溯法:

在解空间内(树),根据剪枝函数(约束函数)来去除不合适的解路径(采用深度优先遍历的方式来遍历接空间树),找到合适的解路径;

 

首先定义一个长度为n的数组blank,初始化全为-1,每个元素代表第i行上防止棋子的列数。

 

剪枝函数的条件:if(x[j]==i||abs(x[j]-i)==abs(j-k)) return false;

 

从树第第一层开始,逐个向下查找,加入到k层,查找失败则返回带k-1层,继续查找。。直到最后blank[n-1]==n  退出并返回

下面是非递归的实现--容易理解

 

void BackTrack(int *blank,int n)// n-皇后的非递归实现
{
	 for(int i=0;i<n;i++)  //初始化n-元组--
	 {
		 blank[i]=0;
	 }

	 int k=0;
	 while(blank[0]!=n)  //当遍历到最后时,blank[0] 会自加到n
	 {
		 while(blank[k]<n&&!place(k,blank[k],blank))  //首先找到复合条件的点
		 {
			 blank[k]++;
		 }

		 if(blank[k]<=n-1)                     
		 {
		     if(k==n-1)   //遍历到最后一层  成功
			 {
		 	 //成功
				 for(int j=0;j<n;j++)
				 {
 	               printf("%d ",blank[j]);
				 }
				 printf("\n"); 
				 blank[k]++;
			 }
	    	 else   //检查到下一个节点
			 {
		    	 k++;
		    	 blank[k]=0;
			 }
		 }
		 else
		 {
			 k--;
			 blank[k]++;
		 }
	 }
}
 

 

分享到:
评论

相关推荐

    objective-c数组全排列算法

    在处理某些问题时,如生成所有可能的组合或者解决排列组合问题,全排列算法是必不可少的工具。全排列指的是从n个不同元素中取出m(m≤n)个元素,按照一定的顺序排列起来,所有的排列情况就构成了全排列。 ...

    java递归实现N个数全排列输出

    在编程领域,全排列是一个经典的算法问题,它涉及到数组或字符串的所有可能的顺序组合。当给定一个包含N个不同元素的集合时,全排列就是要列出所有可能的N!(N的阶乘)种排列方式。在这个场景中,我们将探讨如何使用...

    N个数全排列的非递归算法

    标题 "N个数全排列的非递归算法" 涉及的是计算机科学中的经典问题——全排列。全排列是指从n个不同元素中取出m(m≤n)个元素,按照一定的顺序排成一列的所有可能组合。在这个场景中,非递归算法指的是不依赖递归...

    n后问题---递归回溯法 n后问题---递归回溯法

    n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---递归回溯法 n后问题---...

    全排列-非递归算法

    通过分析和理解这段代码,你可以进一步了解如何使用非递归方法生成全排列,以及如何处理动态添加元素的情况。代码可能涉及到循环、条件判断、数组操作等基本编程概念,通过学习和实践,可以提升对全排列算法的理解和...

    c++代码运用回溯与位运算算法实现N-皇后问题

    本资源使用c++代码实现N-皇后问题并附上研究小论文,实现算法有:回溯法(递归),回溯法(递归)的镜像优化,回溯法(非递归),回溯法(非递归)的镜像优化,位运算算法,位运算算法的镜像优化。N-皇后问题是八皇后问题的...

    非递归法实现n皇后问题

    本资源是数据结构中利用非递归法实现n皇后问题的一个C++代码,仅供参考,欢迎指正

    C语言实现N皇后问题非递归求解

    N皇后问题是一个经典的计算机科学问题,...总的来说,C语言实现的非递归N皇后问题解法避免了递归可能导致的栈溢出问题,同时减少了空间需求。这种方法虽然简单,但能够有效地解决问题,体现了算法设计的简洁性和效率。

    Ackermann 递归与非递归两种解法

    总的来说,理解 Ackermann 函数可以帮助我们更好地了解递归的概念、递归函数的复杂性以及非递归解法的重要性。在编程中,特别是对于计算复杂度高的函数,寻找非递归解决方案往往能提高程序的效率。在 Visual C++ 6.0...

    河内塔问题的非递归解法

    这种技巧对于处理其他递归问题,如树的遍历、图的搜索等问题,也有一定的启发作用。 在提供的压缩包文件"**HanoiTower**"中,可能包含了实现非递归算法的代码示例,你可以进一步学习和研究这些代码,以便更好地掌握...

    N皇后求解问题——递归和回溯方法

    在C语言实现中,"n皇后问题.cpp"和"N皇后非递归.cpp"文件可能分别包含了递归和非递归的代码实现。这些代码通常包含定义棋盘结构、检查冲突、放置皇后、回溯等核心函数。通过阅读和理解这些代码,你可以更深入地了解...

    非递归的输出1-N的全排列实例(推荐)

    算法总体思路是从1,2,3……N这个排列开始,一直计算下一个排列,直到输出N,N-1,……1为止 那么如何计算给定排列的下一个排列? 考虑[2,3,5,4,1]这个序列,从后往前寻找第一对递增的相邻数字,即3,5。那么3...

    n皇后算法递归与非递归

    用递归回溯和非递归的回溯实现N皇后问题。

    编写程序输出前n个正整数的字典序全排列

    使用递归 :-------------输入给出正整数n,输出1到n的全排列,排列的输出顺序为字典序,每种排列占一行,数字间无空格,

    汉诺塔(河内塔)非递归解法

    汉诺塔的非递归解法,十分神奇,值得借鉴! 汉诺塔的非递归解法,十分神奇,值得借鉴! 汉诺塔的非递归解法,十分神奇,值得借鉴! 汉诺塔的非递归解法,十分神奇,值得借鉴! 汉诺塔的非递归解法,十分神奇,值得...

    N皇后问题非递归算法

    N后问题,用非递归的方式去求解。

    n皇后非递归 c++源码实现

    《n皇后非递归C++实现详解》 ...总结,n皇后问题的非递归C++实现主要依赖于回溯算法,通过迭代方式生成所有可能的皇后布局并检查其合法性。理解和实现这种解决方案不仅可以提高编程技能,还能深化对算法思维的理解。

    n后问题--非递归迭代回溯.rar

    n后问题--非递归迭代回溯.rar n后问题--非递归迭代回溯.rar n后问题--非递归迭代回溯.rar n后问题--非递归迭代回溯.rar n后问题--非递归迭代回溯.rar n后问题--非递归迭代回溯.rar

    全排列的非递归实现JAVA

    全排列的非递归实现。 输入1,2,3,4 得到 [1 2 3 4]..........[4 3 2 1]所有24种排列

    N个数全排列c语言算法

    输入N,输出1-N全排列c语言算法,非递归算法................

Global site tag (gtag.js) - Google Analytics