C++标准库中next_permutation和pre_permutation实现原理

    标准库中next_permutation函数:找当前序列中元素排列的下一个排列,按照字典顺序进行排列。比如说数组排列"123",那么它的下一个排列为"132",并且返回true。如果当前序列没有下一个排列,我们返回false,且把当前排列置为最小的排列,比如说:排列"321",因为该排列已经是最大的排列,所以它没有下一个排列。我们把该排列置为"123",并且返回false。
    标准库实现两个重载版本的next_permutation。第一个函数接受两个参数,并且返回一个bool值,第二个函数接受三个参数,也返回一个bool值。
bool next_permutation(_BidIt _First, _BidIt _Last);//第一个参数指数组的开始位置的迭代器,第二个参数指数组结束位置的后一个位置的迭代器。
bool next_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred);//前两个参数和第一个函数中参数表达的意思相同,第三个参数指数组中的元素按照何种序列进行比较。

next_permutation函数的实现原理:我们把数组分割成三个划分,在第一个划分中的所有元素都不需要改变,第二个划分只有一个元素,并且该元素需要和第三个划分中的某个元素进行交换。在第三个划分中,所有元素都需要逆序处理。如图所示:



    重点是我们如何把序列分割成三个划分。首先找到第三个划分和第二个划分的分界线。因为第三个划分按照由右向左按非降序排列,所以它们的分界线是第一对不满足非降序排列的元素中间的位置。第二个划分只有一个元素。剩余的元素自然就成为第一个划分。
    把序列分割以后:我们需要对分割以后的划分进行操作。首先,在第三个划分中,找到第一个大于第二个划分中的元素的位置。比如上图中,在{5,3,1,0}中找到第一个大于{2}的元素的位置,最后找到的是元素3的位置。把2和3进行交换。然后把交换以后的第三个划分逆序。





代码实现如下:直接对序列进行排序:
bool nextPermutation(vector<int> &nums)
{
	int size = nums.size();
	for (int i = size - 1; i > 0; --i)
	{
		//找到第二个划分与第一个划分的分界线
		if (nums[i] > nums[i - 1])
		{
			int val = nums[i - 1];
			int j = size - 1;
			//找到第一大于val值的位置
			for (; j >= i; --j)
			{
				if (nums[j] > val)
					break;
			}
			//交换val值和第一个大于val的值
			swap(nums[i - 1], nums[j]);
			int l = i;
			int r = size - 1;
			//逆序处理
			while (l < r)
			{
				swap(nums[l], nums[r]);
				l++;
				r--;
			}
			return true;
		}
	}
	int start = 0;
	int last = size - 1;
	while (start < last)
	{
		swap(nums[start], nums[last]);
		start++;
		last--;
	}
	return false;
}

标准库中还有prev_permutation函数,找到当前序列的前一个序列,比如说序列"132",返回的是"123"。实现代码如下:

bool prePermutation(vector<int> &nums)
{
	int size = nums.size();
	for (int i = size - 1; i > 0; --i)
	{
		if (nums[i] < nums[i - 1])
		{
			int val = nums[i - 1];
			int j = size - 1;
			for (; j >= i; --j)
			{
				if (nums[j] < val)
					break;
			}
			swap(nums[i - 1], nums[j]);
			int l = i;
			int r = size - 1;
			while (l < r)
			{
				swap(nums[l], nums[r]);
				l++;
				r--;
			}
			return true;
		}
	}
	int start = 0;
	int last = size - 1;
	while (start < last)
	{
		swap(nums[start], nums[last]);
		start++;
		last--;
	}
	return false;
}
时间: 2024-10-11 20:05:13

C++标准库中next_permutation和pre_permutation实现原理的相关文章

STL笔记(6)标准库:标准库中的排序算法

STL笔记(6)标准库:标准库中的排序算法 标准库:标准库中的排序算法The Standard Librarian: Sorting in the Standard Library Matthew Austern http://www.cuj.com/experts/1908/austern.htm?topic=experts 用泛型算法进行排序    C++标准24章有一个小节叫“Sorting and related operations”.它包含了很多对已序区间进行的操作,和三个排序用泛型

c/c++标准库中的文件操作总结

1 stdio.h是c标准库中的标准输入输出库 2 在c++中调用的方法 直接调用即可,但是最好在函数名前面加上::,以示区分类的内部函数和c标准库函数. 3 c标准输入输出库的使用 3.1 核心结构体 FILE结构体 打开一个文件的时候获取它,然后就可以不用管它了. 3.2 核心方法 3.2.1 fopen 第一个字符串是文件的路径. 第二个参数是一个字符串,表示操作该文件的模式,"rb"表示read binary,即以二进制的形式来读该文件. 3.2.2 fseek 第一个参数是F

参考C++STL标准库中对了的使用方法

http://www.cppblog.com/zhenglinbo/archive/2012/09/18/191170.html 参考:http://www.cppblog.com/zhenglinbo/archive/2012/09/18/191170.html 当然是使用c++中的STL 的queue啦.下面简要介绍一下使用方法. 1 准备工作 头文件 #include<queue> 2 声明和定义的方法.STL的队列是泛型模板,支持任何内置和构造类型. 比如对于刚才那个牛奶问题.我把状态

Swift标准库中的协议_012_swift协议

//: Playground - noun: a place where people can play import UIKit //--Swift标准库中的协议---// //1.实例的比较:判断两个实例值是否相同 let a = 4, b = 4 a == b //(Int类型的比较) //自定义结构体类型,进行是否相等的比较 struct Games { var winCount : Int var loseCount : Int } let g1 = Games(winCount: 2

swift标准库中常见的55个协议。

swift标准库中常见的55个协议. 从协议名结尾字面上我们可以将Protocol分为able.Type.Convertible 三类 从功能角度上来讲的话可以总结为: 功能添加型(able结尾) "可以做什么?" 举例: Hashable: 给你的实例添加一个生成哈希值的功能. Equatable: 给你的实例添加一个判断相等的功能. 2.类型对比型(Type结尾) "这个实例是什么?" 举例: CollectionType: swift中所有的集合类型都要遵守的

linux下Qt调用非标准库中的函数调用----------如pthread_create、pthread_cond_***、、

在Linux下Qt中使用POSIX标准的pthread_creaet函数调用创建新线程,使用如下代码后编译通过 extern "C" { #include <pthread.h> } 但是运行后发现并未成功创建新线程,并且无报错!!! (编译链接时有添加:-lpthread) 其中原因本人尚不清楚... 并且pthread_mutex_*** (互斥锁).pthread_cond_*** (条件变量) 等相关函数估计也无效... 后来借鉴网友提供的方法:将C文件创建成函数库

《深入实践C++模板编程》之六——标准库中的容器

1.容器的基本要求 a.并非所有的数据都可以放进容器当中.各种容器模板对所存数据类型都有一个基本要求——可复制构造.将数据放进容器的过程就是通过数据的复制构造函数在容器内创建数据的一个副本的过程. b.容器中必须有若干与所存数据类型有关的嵌套定义类型. C::value_type 容器所存数据类型 C::reference 容器数据的引用类型 C::const_reference 容器数据的只读引用类型 C::size_type 容器容量类型,通常是一个无符号整数类型 c.除嵌套类型定义外,容器

C++11标准库中cstdio头文件新增的5个格式化I/O函数学习

刚开始学网络编程,稍微扩展书上的简单C/S程序时,发现以前太忽略标准I/O这一块,查官网发现C++11新增了几个格式化I/O函数. snprintf    将格式化输出写入到有大小限制的缓存中 vfscanf     从流中读取数据到可变参数列表中 vscanf      读取格式化数据到可变参数列表中 vsnprintf  从可变参数列表中写入数据到有大小限制的缓存中 vsscanf     从字符串中读取格式化数据到可变参数列表中 主要谈谈snprintf,后面4个都是辅助可变参数列表的.

标准库中的管道操作

----------------------------------------------------------------------------------------------------------- #include <stdio.h>#include <stdlib.h>#include <memory.h> int main(void){    FILE *fp;    //命令执行的结果放置在fp指向的结构体缓冲中    fp = popen(&q