数据结构基础(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 ...
随机推荐
- Android------Android.mk调用shell脚本
$(info $(shell ($(LOCAL_PATH)/echo_test.sh)))
- 手势监听GestureDetector 案例
以下只做长按和甩出(用户按下朝某一方向甩动手指)案例 OnGestureListener可以查看到更多的手势事件 案例 package com.qf.mobliesafe.activity; impo ...
- 计算机网络之套接字SOCKET
当某个应用进程启动系统调用时,控制权就从应用进程传递给了系统调用接口. 此接口再将控制权传递给计算机的操作系统.操作系统将此调用转给某个内部过程,并执行所请求的操作. 内部过程一旦执行完毕,控制权就又 ...
- Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 2 部分: DTrace
DTrace的原理本系列文章详细地介绍了一个 Linux 下的全新的调式.诊断和性能测量工具 Systemtap 和它所依赖的基础 kprobe 以及促使开发该工具的先驱 DTrace 并给出实际使用 ...
- 快速排序quick_sort(python的两种实现方式)
排序算法有很多,目前最好的是quick_sort:unstable,spatial complexity is nlogN. 快速排序原理 python实现 严蔚敏的 datastruct书中有伪代码 ...
- Spring常用配置(二)
OK,上篇博客我们介绍了Spring中一些常见的配置,上篇博客中介绍到的都是非常常见的注解,但是在Spring框架中,常见的注解除了上篇博客提到的之外,还有许多其他的注解,只不过这些注解相对于上文提到 ...
- Java异常处理-----抛出处理
抛出处理 定义一个功能,进行除法运算例如(div(int x,int y))如果除数为0,进行处理. 功能内部不想处理,或者处理不了.就抛出使用throw new Exception("除数 ...
- Cocos2D与SpriteBuilder的问题在哪提问
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道Cocos2D的教程中文版的非常少,注意我没有说Coc ...
- CoreAnimation中layer动画闪烁的原因及解决
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 网上有一段Core Animation层动画的例子,是将vie ...
- 删除表中重复行SQL
delete from table_name a where rowid < (select max(rowid) from table_name b where a.col1 = b.col1 ...