数据结构基础(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 ...
随机推荐
- JavaScript switch 语句
switch 语句用于基于不同的条件来执行不同的动作. JavaScript switch 语句 请使用 switch 语句来选择要执行的多个代码块之一.你可以在JavaScript编程实战中了解怎么 ...
- django的流程和命令行工具
django实现流程django #安装: pip3 install django 添加环境变量 #1 创建project django-admin startproject mysite ---my ...
- OSTC 2015
上周六去北京参加了OSTC 2015开源技术大会,并分享了<Spark技术内幕>,主要涵盖了Spark Core的核心实现.我主要以WordCount为例,讲解了任务调度的具体实现,资源分 ...
- React Native之ListView实现九宫格效果
概述 在安卓原生开发中,ListView是很常用的一个列表控件,那么React Native(RN)如何实现该功能呢?我们来看一下ListView的源码 ListView是基于ScrollView扩展 ...
- android的activity栈管理
在进行BlackBerry程序开发的时候,BlackBerry提供了一个管理Screen的栈,用来从任何地方来关闭位于最上一层的Screen,使用UiApplication.getUiApplicat ...
- 5. React 组件的协同使用 组件嵌套和Mixin
组件是React的核心,构建大型项目时多个组件之间需要进行协同使用.可以从横向和纵向两个角度来实现组件的协同使用,纵向的协同使用就是组件嵌套,横向的协同使用就是Mixin(抽取公共方法 ...
- 11 ContextMenu 上下文菜单按钮
ContextMenu 上下文菜单 在res下的menu里写菜单项 在逻辑代码中 写OnCreateContextMenu() 方法 将菜单项添加到菜单 对菜单项进行监听 onContextItemS ...
- 饮一盏Bug留香,唱一曲项目飞扬
沿途的风景 牵挂的项目 两情迢迢 学生档案管理项目在2月的末尾从稍带寒意的季节里完成了第一次迭代,验收的结果不尽善尽美,演示的功能也惨不忍睹,各种"关爱"的点评充斥耳旁 ...
- SpriteBuilder中使用GUI界面快速搭建RPG游戏中的地图名显示动画
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 在RPG游戏中我们在进入一个新的场景时,比如一个房间,一个村庄, ...
- >/dev/null 2>&1
>/dev/null 2>&1 大部分在 crontab 计划任务中都会年到未尾带 >/dev/null 2>&1,是什么意思呢? > 是重定向 /dev ...