八皇后--栈递归实现

版权声明:转载请注明出处,谢谢合作 https://blog.csdn.net/qq_40738840/article/details/83929919

说明

该文主要为练习数据结构的栈结构,所以将会一步步实现栈结构后,再使用栈的基本功能,如建栈,出栈,入栈,而不是直接调用库函数

数据结构

  • 逻辑结构: 栈
  • 物理结构: 动态数组实现

算法

  • 递归思想

算法描述

  1. 选择棋盘第一行的任意一个点作为当前点p:(x,y)
  2. 结束条件:栈满或是遍历完所有点
  3. 判断点p是否满足攻击条件:在同一行或同一列或同一斜线(正负45°),若满足转第4步,否则转第5步
  4. 若y<8,当前点的y++,转第2步;否则出栈,出栈点y++,作为当前点,转第3步
  5. 当前点入栈,x++,y=1,转第3步

代码实现思路(按顺序实现)

实现栈的结构即基本功能

定义栈结构体
实现初始化空栈
实现入栈功能
实现遍历栈功能(1.为了测试建栈与入栈功能;2.为了输出结果)
实现出栈功能

利用已有的栈结构及功能实现八皇后求解

实现攻击条件是否满足功能
递归实现模拟查找功能

C++/C代码

#include<iostream>
using namespace std;
#include"stdlib.h"

#define STACK_SIZE 8
//点坐标 
typedef struct 
{
	int x;
	
	int y;	
} Pos;

//动态数组 
typedef struct
{
	Pos *base;//栈底,相当于数组头指针 
	
	Pos *top;//栈底 
	
	int stacksize;//可用空间 
	
}SqStack;

//初始化空栈 
void InitStack_Sq(SqStack &S)
{
	S.base = (Pos*)malloc(STACK_SIZE*sizeof(Pos));//申请空间 
	
	S.top = S.base;//栈底栈顶相同时代表栈为空 
	
	S.stacksize = STACK_SIZE;//可用空间 
}

//入栈 
void Push_Sq(SqStack &S, Pos pos)
{
	if(S.top - S.base >= STACK_SIZE)
	{
		cout<<"栈满!"<<endl;
		
		return;
		
	}
	
	S.top->x = pos.x;
	
	S.top->y = pos.y;
	
	S.top++;//更新栈顶位置 
}

//出栈 
Pos Pop_Sq(SqStack &S)
{
	//栈空 
	if(S.top == S.base)
	{
		cout<<"栈空!"<<endl;
		
		Pos pos;
		
		pos.x = -1;
		
		pos.y = -1;
		
		return pos;
	}
	
	S.top--;
	
	Pos pos;
	
	pos.x = S.top->x;
	
	pos.y = S.top->y;
	
	//cout<<"出栈   x: "<<S.top->x<<"  y: "<<S.top->y<<endl;
	 
	 return pos;
}

//遍历栈 
void TraverseStack_Sq(SqStack S)
{
	if(S.base == NULL)
	{
		cout<<"栈不存在!"<<endl;
		
		return;
	}
	
	if(S.base == S.top)
	{
		cout<<"栈空!"<<endl;
		
		return;
	}
	
	//坐标输出 
	for(Pos *p = S.base; p<S.top; p++)
	{
		cout<<"x:    "<<p->x<<"      y:    "<<p->y<<endl;
	}
	cout<<endl;
	
	//图形输出 
	cout<<"-------------------图形验证-------------------"<<endl<<endl; 
	for(Pos *p = S.base; p<S.top; p++)
	{
		for(int j = 1; j < 9; j++)
		{
			if(j == p->y)cout<<"Q   ";
			
			else cout<<"_   ";
			
		}
		cout<<endl<<endl;
	//	cout<<"x:    "<<p->x<<"      y:    "<<p->y<<endl;
	}
	
 } 
 
 //判断当前点是否与已有点相互攻击 
 bool IsAttack(SqStack S, Pos pos)
 {	
	//栈空,即可选序列中无点 
	if(S.base == S.top)
	{
		return false;
	}
	
	//遍历:一旦位置满足攻击条件,立刻退出循环 
	bool bflag = false;
	
	for(Pos *p = S.base; p < S.top; p++ )
	{
		//前4个条件为不在同一行、列、斜线(+-45度)
		//后两个条件是为递归函数做铺垫,坐标需在合理范围内,超出该范围归为可攻击 
		if(p->x == pos.x || p->y == pos.y || 
		  (p->x - pos.x) == (p->y - pos.y) || 
		  (p->x + p->y) == (pos.x + pos.y) ||
		   pos.x > STACK_SIZE || pos.y > STACK_SIZE)
		   
		{
			bflag = true;
			
			break;
		}
	}
	
	return bflag;
	
}


//递归寻找适合点序列 
void RecursionFind(SqStack &S, Pos pos)
{
	//两个递归结束条件:1.栈满(找到序列); 2.遍历完所有点
	//因为是先判断递归条件,若满足才入栈。所以栈满条件的满足总是慢条件2一步 
	//若是将条件二改为(pos.x == STACK_SIZE && pos.y == STACK_SIZE) ,若是还未栈满,达到该条件直接就返回了,所以将缺少第STACK_SIZE行的元素 
	if((S.top - S.base == S.stacksize) || (pos.x == STACK_SIZE && pos.y > STACK_SIZE))return;
	
	 
	if(!IsAttack(S, pos))//不攻击 
	{
		Push_Sq(S,pos);//该点入栈 
	//	cout<<endl<<" 入栈:"<<pos.x<<endl;
		if(pos.x < STACK_SIZE)//若是还有下一行,则移动到下一行递归求解 
		{
			pos.x++;//下一行 
			
			pos.y = 1;//从第一个开始 
			
			RecursionFind(S,pos);
		}
		
	}
	else//互相攻击 
	{
		if(pos.y < STACK_SIZE)//一行没遍历完,继续遍历 
		{
			pos.y++;
			
			RecursionFind(S,pos);
		}
		else//一行已遍历完 ,说明此路不通 
		{
			pos = Pop_Sq(S);//出栈 
			
			pos.y++; 
				
			RecursionFind(S,pos);
		}
	}
} 


int main()
{
	SqStack S;
	
	int n;
	Pos pos;
	
	InitStack_Sq(S);
	
/*	cout<<"请输入需要的点个数: ";
	cin>>n;
	
	for(int i = 0; i < n; i++)
	{
		cout<<"请输入点的横纵坐标: ";
		cin>>pos.x>>pos.y;
		
		Push_Sq(S, pos);
				
	}	
*/	
//	TraverseStack_Sq(S);

//起始点x必须为 1 
	pos.x = 1;
	
	while(true)
	{
		cout<<"请选择第一行的纵坐标y (1~8):";
		cin>>pos.y;
		
		if(pos.y > 0 && pos.y < STACK_SIZE +  1)break;
	}
	RecursionFind(S,pos);
	
	cout<<endl<<"--------------一种可行方案------------------- " <<endl<<endl; 
	TraverseStack_Sq(S);	
//	Pos p = Pop_Sq(S);
	
	//cout<<"pop: x: "<<p.x<<"  y: "<<p.y<<endl;
	//pos.x = 100; pos.y = 1000;
	
	//cout<<IsAttack(S, pos)<<endl; 
	//Pop_Sq(S);
	
	//TraverseStack_Sq(S);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40738840/article/details/83929919