算法实现总结 - C/C++

算法实现 - C/C++

  • 前言
  • [1. 数据结构类](#1. 数据结构类)
  • [2. 常见算法类](#2. 常见算法类)
    • [2.1 n皇后](#2.1 n皇后)
  • 参考文献

前言

总结积累平时研究的算法,不定时更新,便于形成体系。

积累习惯:

  1. 一张图形象描述问题
  2. 该算法触动/记忆点
  3. 算法策略(分递二,回贪动)
  4. 算法代码含关键理解点

1. 数据结构类

2. 常见算法类

2.1 n皇后

25年下半年软考算法题。

当时脑子里只有queen[i][j]的二维解法,案例使用k表行,queen[k]表列时有点懵(没这个概念)。虽然跌跌撞撞写出了大部分,但主要是题目引导和举实例试出来的。

策略:回溯法

法一: 案例解法

c 复制代码
#include<stdio.h>
#include<math.h>
#define N 100			// 最多摆放100个皇后 
int n,queen[N];			// 关键理解:queen[k] 表示 "第 k 行的皇后放在第queen[k]列"(行和列均从 0 开始计数)。
						// 例如:queen[0] = 1 表示第 0 行的皇后在第 1 列。
						// 这种设计天然避免了 "同一行多个皇后" 的冲突(因为每行只存一个列号)。
int num = 0;			// 总共有多少方案

void Putqueen(int k)	// 假设前k个皇后已经摆好,现在摆放第K个皇后
{
	int i,j;
	if(k==n)			// 终止条件:第 0 到第 n-1 行的皇后都已摆放完成(共 n 行,即所有皇后都放好了)。
	{
		for(i=0;i<n;i++)
		{
			printf("(%d,%d)\t",i+1,queen[i]+1);		// 输出时 i+1 和 queen[i]+1 是将 "0 开始的索引" 转换为 "1 开始的棋盘坐标"(符合日常习惯)。
		}
		printf("\n");
		num ++;
	}
	else
	{
		for(i=0;i<n;++i)		// 尝试将第k行皇后放在第i列 (同一行一例一列试)
		{
			for(j=0;j<k;++j)	// 检查当前位置(i列)与前k行皇后是否冲突
			{
				if(i==queen[j]||abs(queen[j]-i)==abs(j-k))		// 冲突条件:同列 或 同对角线
				{
					break;		//有冲突,跳出检查,尝试下一列
				}
			}
			if(j==k)			// 前k行都无冲突(当前列i合法)
			{
				queen[k]=i;		// 记录第k行皇后在第i列
				Putqueen(k+1);	// 递归摆放下一行(第k+1行)
			}	
		}
	}
	
}

int main()
{
	scanf("%d",&n);			// 输入皇后数量n
	Putqueen(0);			// 从第0行开始摆放皇后
	printf("num: %d\n\n", num);			// 输出方案数量
	return 0;	
}

法二:法一上优化冲突检查方式

空间换时间,尤其适合求解较大 n 的问题.

c 复制代码
#include<stdio.h>
#include<math.h>
#define N 100			    //最多摆放100个皇后 
int n;
int queen[N];
int visited[3][2*N-2];      // visited数组:记录列、主对角线、副对角线是否被占用
                            // 其中:
                            // visited[0][i]:标记第i列是否有皇后(列冲突)
                            // visited[1][k+i]:标记主对角线(k+i为定值)是否有皇后(主对角线冲突)
                            // visited[2][k-i+n]:标记副对角线(k-i为定值,加n避免负数索引)是否有皇后(副对角线冲突)

/*
    核心思路:用visited数组提前记录 "已被皇后占用的列和对角线",每次检查冲突时无需遍历前 k 行,直接通过 3 个索引判断:
        列冲突:第 i 列是否被占用(visited[0][i]);
        主对角线冲突:对于第 k 行第 i 列,主对角线的特征是 "行 + 列 = k+i"(同一主对角线上的所有位置,行 + 列的值相同),因此用visited[1][k+i]标记;
        副对角线冲突:对于第 k 行第 i 列,副对角线的特征是 "行 - 列 = k-i"(同一副对角线上的所有位置,行 - 列的值相同),但k-i可能为负数,因此加 n(偏移量)避免数组索引为负,用visited[2][k-i+n]标记。
    操作:摆放皇后时,将对应的列、主对角线、副对角线标记为 "占用"(置 1);回溯时(递归返回后),再重置为 "未占用"(置 0),确保不影响其他分支的尝试。
*/
void Putqueen(int k)
{
	int i,j;
	if(k==n)		    //递归出口 
	{
		for(i=0;i<n;i++)
			printf("(%d,%d)\t",i+1,queen[i]);
		printf("\n");
	}
	else
	{
		for(i=0;i<n;i++)        // 检查第k行第i列是否与前k行皇后冲突
		{
			if(!visited[0][i]&&!visited[1][k+i]&&!visited[2][k-i+n])	//k-i可能为负,所以加n 
			{
				queen[k]=i;
				visited[0][i]=visited[1][k+i]=visited[2][k-i+n]=1;
				Putqueen(k+1);
				visited[0][i]=visited[1][k+i]=visited[2][k-i+n]=0;
			}
		}
	}
	
}

int main()
{
	scanf("%d",&n);
	Putqueen(0);
	return 0;	
}

/*
1. 时间效率显著提升:通过 "空间换时间",将冲突检查从 O (k) 优化为 O (1),总时间复杂度从O(n! * n²)降至O(n!),尤其在 n 较大时(如 n=12 以上),运行速度会明显更快。
2. 空间开销可控:虽然增加了visited数组,但空间复杂度仍为 O (n),没有本质增加,属于 "用少量空间换大幅时间优化" 的典型做法。
*/

参考文献

  1. n 皇后:https://blog.csdn.net/weixin_45953673/article/details/104468683
相关推荐
林shir22 分钟前
Java基础1.7-数组
java·算法
Jeremy爱编码1 小时前
leetcode课程表
算法·leetcode·职场和发展
甄心爱学习1 小时前
SVD求解最小二乘(手写推导)
线性代数·算法·svd
努力学算法的蒟蒻1 小时前
day46(12.27)——leetcode面试经典150
算法·leetcode·面试
Blockbuater_drug1 小时前
InChIKey: 分子的“化学身份证”,从哈希原理到全球监管合规(2025)
算法·哈希算法·inchikey·rdkit·分子表达·化学信息学
ComputerInBook2 小时前
函数调用栈帧分析(Windows平台)
c语言·windows·编译原理·汇编语言·c++语言
橙汁味的风2 小时前
2EM算法详解
人工智能·算法·机器学习
维构lbs智能定位2 小时前
北斗卫星导航定位从核心框架到定位流程详解(一)
算法·北斗卫星导航定位系统
byzh_rc2 小时前
[算法设计与分析-从入门到入土] 动态规划
算法·动态规划
Halo_tjn2 小时前
Java List集合知识点
java·开发语言·windows·算法·list