数据结构基础(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 ...
随机推荐
- CNN在中文文本分类的应用
深度学习近一段时间以来在图像处理和NLP任务上都取得了不俗的成绩.通常,图像处理的任务是借助CNN来完成的,其特有的卷积.池化结构能够提取图像中各种不同程度的纹理.结构,并最终结合全连接网络实现信息的 ...
- 两个activity之间透明过渡效果和经验
来看下效果图: 大致效果解释: 1. 当用户点击登录时logo下滑一定距离 2. 下滑后旋转90时 变化图标 3. 继续旋转90度 4. 然后移动到左上角 透明度渐变到上个activity 最后销毁当 ...
- 有一个排序二叉树,数据类型是int型,如何找出中间大的元素。
void tree2Dll(TNode* root, TNode*& tail) { if (!root) { return; } if (root->left) { tree2Dll( ...
- Redis监控工具,命令和调优
Redis监控工具,命令和调优 1.图形化监控 因为要对Redis做性能测试,发现了GitHub上有个python写的RedisLive监控工具评价不错.结果鼓捣了半天,最后发现其主页中引用了Goog ...
- Dynamics CRM build numbers
Dynamics CRM build numbers CRM各大版本及补丁列表,整理的很全
- CocoaChina(总结)升级到xcode8遇到的问题及解决方案
此总结由CocoaChina论坛版主wo709128079及广大坛友共同汇总.>>查看原帖 升级Xcode8已是必然,升级iOS 10的用户不能说大有人在,应该也不会少,楼主听说,如果不升 ...
- FORM开发之键性弹性域开发
1.创建表时带有键弹性域字段 SUMMARY_FLAG VARCHAR2(1) , /* 必须有此字段 */ ENABLED_FLAG VARCHAR2(1) , /* 必须有此字段 */ START ...
- Swift中不用桥接文件和.h头文件直接和C代码交互的方法
我们知道一般情况下Swit要想调用obj-c,c或c++代码必须通过obj-c以及桥接文件才可以办到,但是对于某些简单的代码,我们可以跳过桥接文件和.h头文件,直接和C代码交互呢! 我们再Projec ...
- java之异常处理
异常Exception我们分为 |--RuntimeException运行期异常,我们需要修正代码 |--非RuntimeException 编译期异常,必须处理的,否则程序编译不通过 异常有两种处理 ...
- 如何在苹果手机上安装自制的AD证书
写这篇博文的契机是有人已经实现了CRM在用自制证书部署IFD后,在手机安装上自制证书后即可登录官方移动端APP,因为之前很多人都尝试过只要是自制证书部署的IFD就无法使用官网手机APP,而本人实验下来 ...