数据结构基础(3) --Permutation & 插入排序
Permutation(排列组合)
排列问题:
设R = {r1, r2, ... , rn}是要进行排列的n个元素, Ri = R-{ri}; 集合X中元素的全排列记为Permutation(X), (ri)Permutation(X)表示在全排列Permutation(X)的每一个排列前加上前缀ri得到的排列.
R的全排列可归纳定义如下:
当n=1时,Permutation(R)={r},r是集合R中唯一的元素;
当n>1时,Permutation(R)由(r1)Permutation(R1),(r2)Permutation(R2), ..., (rn)Permutation(Rn)构成。
依次递归定义,则可设计产生Permutation(X)的递归算法如下:
template <typename Type>
void permutation(Type *array, int front, int last)
{
//已经递归到了最后一个元素
if (front == last)
{
//打印输出
for (int i = 0; i < front; ++i)
{
cout << array[i] << ' ';
}
cout << array[front] << endl;
return ;
}
else
{
for (int i = front; i <= last; ++i)
{
// 不断的从下标为[front ~ last]的元素中选择一个元素
//作为当前序列的开头元素
std::swap(array[front], array[i]);
permutation(array, front+1, last);
std::swap(array[front], array[i]);
}
}
}
算法说明:
算法Permutation(array, k, m)递归地产生所有前缀是array[0:k-1],且后缀是array[k:m]的全排列的所有排列.函数调用(list, 0, n-1)则产生list[0:n-1]的全排列.
算法演示:
char str[] = “abc”;的递归调用过程如图:
小结:
虽然我们自己实现了Permutation, 但C++ STL中也实现了std::next_permutation算法, 在一般应用中, 我比较推荐使用STL中已经实现好的next_permutation, 毕竟STL的代码质量还是非常高的, 而且速度一点也不逊色于我们的实现;
插入排序
插入排序是低级排序中速度最快的一种(冒泡/选择/插入排序效率均为O(N^2)),但是跟快速排序(NlogN),归并排序(NlogN)还是有一定的差距的⊙﹏⊙b汗!
算法思想:
不断的从尚未排序的序列中选择一个元素插入到已经排好序的序列中(当然,会有一个选择插入位置的过程:选择一个位置, 该位置前的元素都比该元素小, 该位置后的元素都比该元素大),类似于现实生活中的斗地主的摸排过程.
//实现与解析
/**说明:
outer:第一个未排序的元素
inner:搜索第一个小于tmp的元素的位置
tmp: 用于暂存第一个尚未排序的元素
*/
template <typename Type>
void insertionSort(Type *begin, Type *end) throw (std::range_error)
{
if ((begin == end) || (begin == NULL) || (end == NULL))
throw std::range_error("pointer unavailable");
//假设第一个元素已经排好序了
for (Type *outer = begin+1; outer < end; ++outer)
{
Type tmp = *outer; //暂存第一个未排序的元素
Type *inner = outer;
//inner 不断寻找一个位置(*(inner-1) <= tmp),
//使得tmp->*inner(tmp所保存的值插入到inner位置)
while (inner > begin && *(inner-1) > tmp)
{
*inner = *(inner-1); //元素后移
-- inner; //指针前移
}
*inner = tmp; //将元素插入已排序序列
}
}
template <typename Iter>
void insertionSort(Iter begin, Iter end)
{
return insertionSort(&(*begin), &(*end));
}
/**insertionSort_2算法的由来:
可以使用*begin(序列的第一个元素)作为哨兵,
这样就可以省去insertionSort 中第15行的inner > begin判断,
但付出的代价是begin所指向的位置不能再存储有用的数据,
只能被用作排序的哨兵 -> 以空间换时间(个人感觉没什么必要...)
*/
template <typename Type>
void insertionSort_2(Type *begin, Type *end) throw (std::range_error)
{
if ((begin == end) || (begin == NULL) || (end == NULL))
throw std::range_error("pointer unavailable");
for (Type *outer = begin+2; outer < end; ++outer)
{
*begin = *outer;
Type *inner = outer;
//因为*begin不可能 > *begin, 所以该循环一定会退出
while (*(inner-1) > *begin)
{
*(inner) = *(inner-1);
--inner;
}
*inner = *begin;
}
}
附-permutation与std::next_permutation测试代码
int main()
{
vector<char> str;
for (char ch = 'a'; ch <= 'c'; ++ch)
str.push_back(ch);
permutation(&(*str.begin()), 0, 2);
cout << "----------" << endl;
typedef vector<char>::iterator Iter_type;
do
{
for (Iter_type iter = str.begin(); iter != str.end(); ++iter)
cout << *iter << ' ';
cout << endl;
}
while (std::next_permutation(str.begin(), str.end()));
return 0;
}
数据结构基础(3) --Permutation & 插入排序的更多相关文章
- 算法与数据结构基础 - 哈希表(Hash Table)
Hash Table基础 哈希表(Hash Table)是常用的数据结构,其运用哈希函数(hash function)实现映射,内部使用开放定址.拉链法等方式解决哈希冲突,使得读写时间复杂度平均为O( ...
- 算法与数据结构基础 - 贪心(Greedy)
贪心基础 贪心(Greedy)常用于解决最优问题,以期通过某种策略获得一系列局部最优解.从而求得整体最优解. 贪心从局部最优角度考虑,只适用于具备无后效性的问题,即某个状态以前的过程不影响以后的状态. ...
- 算法与数据结构基础 - 数组(Array)
数组基础 数组是最基础的数据结构,特点是O(1)时间读取任意下标元素,经常应用于排序(Sort).双指针(Two Pointers).二分查找(Binary Search).动态规划(DP)等算法.顺 ...
- Python之数据结构基础
一.数据结构基础 a.什么是数据结构 b.数据结构的分类 c.列表 import random from timewrap import ...
- 数据结构基础(1)--数组C语言实现--动态内存分配
数据结构基础(1)--数组C语言实现--动态内存分配 基本思想:数组是最常用的数据结构,在内存中连续存储,可以静态初始化(int a[2]={1,2}),可以动态初始化 malloc(). 难点就是数 ...
- php数据结构课程---1、数据结构基础介绍(程序是什么)
php数据结构课程---1.数据结构基础介绍(程序是什么) 一.总结 一句话总结: 程序=数据结构+算法 设计好数据结构,程序就等于成功了一半. 数据结构是程序设计的基石. 1.数据的逻辑结构和物理结 ...
- 算法与数据结构基础 - 堆(Heap)和优先级队列(Priority queue)
堆基础 堆(Heap)是具有这样性质的数据结构:1/完全二叉树 2/所有节点的值大于等于(或小于等于)子节点的值: 图片来源:这里 堆可以用数组存储,插入.删除会触发节点shift_down.shif ...
- 算法与数据结构基础 - 广度优先搜索(BFS)
BFS基础 广度优先搜索(Breadth First Search)用于按离始节点距离.由近到远渐次访问图的节点,可视化BFS 通常使用队列(queue)结构模拟BFS过程,关于queue见:算法与数 ...
- 算法与数据结构基础 - 二叉树(Binary Tree)
二叉树基础 满足这样性质的树称为二叉树:空树或节点最多有两个子树,称为左子树.右子树, 左右子树节点同样最多有两个子树. 二叉树是递归定义的,因而常用递归/DFS的思想处理二叉树相关问题,例如Leet ...
随机推荐
- MySQL系列教程(四)
文件打开数(open_files) 我们现在处理MySQL故障时,发现当Open_files大于open_files_limit值时,MySQL数据库就会发生卡住的现象,导致Nginx服务器打不开相应 ...
- springMVC源码分析--ModelAndViewContainer和ModelMap
ModelAndViewContainer主要是用来返回Model对象的,在ModelAndViewContainer中有defaultModel和redirectModel, defaultMode ...
- ubuntu ssh 防止登陆断开
client 端: echo -e '\nServerAliveInterval 30' >> ~/.ssh/ssh_config server 端: echo -e '\nClientA ...
- Web Worker Best Practices
使用Web Worker可以把一些比较计算量相对大的阻塞浏览器响应的计算放在单独的线程里计算. 请求优化 构造Worker的时候需要给定js的链接URL,worker内部请求js运行代码.假如work ...
- iOS开源加密相册Agony的实现(六)
简介 虽然目前市面上有一些不错的加密相册App,但不是内置广告,就是对上传的张数有所限制.本文介绍了一个加密相册的制作过程,该加密相册将包括多密码(输入不同的密码即可访问不同的空间,可掩人耳目).Wi ...
- 使用GDB调试STL容器
GDB中print方法并不能直接打印STL容器中保存的变量,想知道STL容器保存的变量,使用如下办法: 1. 创建文件~/.gdbinit: # # STL GDB evaluators/views/ ...
- 【mybatis深度历险系列】mybatis的框架原理+入门程序解析
在前面的博文中,小编介绍了springmvc的相关知识点,在今天这篇博文中,小编将介绍一下mybatis的框架原理,以及mybatis的入门程序,实现用户的增删改查,她有什么优缺点以及mybatis和 ...
- Java面向对象要点
面向对象: 一.基本概念 类与对象的基本概念: 1.void类型是不需要返回值的,其他类型全部都需要返回值. public void tell(){ ...
- Scala:提取器(Extractor)
http://blog.csdn.net/pipisorry/article/details/52902671 提取器是从传递给它的对象中提取出构造该对象的参数. Scala 标准库包含了一些预定义的 ...
- Support Annotation Library使用详解
概述 Support Annotation Library是在Android Support Library19.1版本开始引入的一个全新的函数包,它包含了诸多有用的元注解.用来帮助开发者在编译期间发 ...