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

算法实现 - C/C++

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

前言

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

积累习惯:

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

1. 数据结构类

2. 常见算法类

2.1 n皇后

25年下半年软考算法题。

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

策略:回溯法

法一: 案例解法

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
相关推荐
绿算技术19 分钟前
Solidigm联合绿算技术共同发布《面向 SOHO AI 推理的存储扩展方案》技术白皮书
人工智能·科技·算法·架构·spark
繁星蓝雨20 分钟前
C++设计原理———重载(extern “C“的由来、顺序依赖、语义依赖、overload、名称修饰符、对象操作、运算符重载、新增运算符、枚举和布尔类型)
c语言·c++·extern c·overload·重载·语义依赖·顺序依赖
handler0124 分钟前
【Linux】虚拟地址空间解析
linux·运维·c++·线程·进程·虚拟地址空间·虚拟地址
(Charon)27 分钟前
【C++】网络缓冲区设计(二):Ring Buffer环形缓冲区、head/tail与跨界读写
开发语言·c++
码匠许师傅37 分钟前
【设计模式精讲】24.观察者模式(Observer)
c++·观察者模式·设计模式·uml
EDPJ1 小时前
(2026|IPI|我的论文投稿中,PSP 超轻量采样算法,轻量化架构探索/早融合+头压缩)LUMIN:面向工业异常检测的轻量级通用制造检测网络
算法·计算机视觉·架构·异常检测·采样算法
imgsq1 小时前
S-57 数据解剖:把一个 ENC 文件拆给你看
c++·数据可视化
我不会起名字3221 小时前
一天一道算法题(29):单调栈
java·数据结构·python·算法·leetcode·golang·单调栈
SuperByteMaster1 小时前
编译器将unsigned short 整体提升int和unsigned short 在内存中的分配2byte的理解
c语言
迷茫、Peanut1 小时前
中断的时钟
c++