数据结构基础(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)的递归算法如下:

  1. template <typename Type>  
  2. void permutation(Type *array, int front, int last)  
  3. {  
  4.     //已经递归到了最后一个元素  
  5.     if (front == last)  
  6.     {  
  7.         //打印输出  
  8.         for (int i = 0; i < front; ++i)  
  9.         {  
  10.             cout << array[i] << ' ';  
  11.         }  
  12.         cout << array[front] << endl;  
  13.         return ;  
  14.     }  
  15.     else  
  16.     {  
  17.         for (int i = front; i <= last; ++i)  
  18.         {  
  19.             // 不断的从下标为[front ~ last]的元素中选择一个元素  
  20.             //作为当前序列的开头元素  
  21.             std::swap(array[front], array[i]);  
  22.             permutation(array, front+1, last);  
  23.             std::swap(array[front], array[i]);  
  24.         }  
  25.     }  
  26. }  

算法说明:

算法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汗!

算法思想:

不断的从尚未排序的序列中选择一个元素插入到已经排好序的序列中(当然,会有一个选择插入位置的过程:选择一个位置, 该位置前的元素都比该元素小, 该位置后的元素都比该元素大),类似于现实生活中的斗地主的摸排过程.


  1. //实现与解析  
  2. /**说明: 
  3.     outer:第一个未排序的元素 
  4.     inner:搜索第一个小于tmp的元素的位置 
  5.     tmp:  用于暂存第一个尚未排序的元素 
  6. */  
  7. template <typename Type>  
  8. void insertionSort(Type *begin, Type *end) throw (std::range_error)  
  9. {  
  10.     if ((begin == end) || (begin == NULL) || (end == NULL))  
  11.         throw std::range_error("pointer unavailable");  
  12.   
  13.     //假设第一个元素已经排好序了  
  14.     for (Type *outer = begin+1; outer < end; ++outer)  
  15.     {  
  16.         Type tmp = *outer;   //暂存第一个未排序的元素  
  17.         Type *inner = outer;  
  18.   
  19.         //inner 不断寻找一个位置(*(inner-1) <= tmp),  
  20.         //使得tmp->*inner(tmp所保存的值插入到inner位置)  
  21.         while (inner > begin && *(inner-1) > tmp)  
  22.         {  
  23.             *inner = *(inner-1);    //元素后移  
  24.             -- inner;               //指针前移  
  25.         }  
  26.         *inner = tmp;               //将元素插入已排序序列  
  27.     }  
  28. }  
  29.   
  30. template <typename Iter>  
  31. void insertionSort(Iter begin, Iter end)  
  32. {  
  33.     return insertionSort(&(*begin), &(*end));  
  34. }  
  1. /**insertionSort_2算法的由来: 
  2.     可以使用*begin(序列的第一个元素)作为哨兵, 
  3.     这样就可以省去insertionSort 中第15行的inner > begin判断, 
  4.     但付出的代价是begin所指向的位置不能再存储有用的数据, 
  5.     只能被用作排序的哨兵 -> 以空间换时间(个人感觉没什么必要...) 
  6. */  
  7. template <typename Type>  
  8. void insertionSort_2(Type *begin, Type *end) throw (std::range_error)  
  9. {  
  10.     if ((begin == end) || (begin == NULL) || (end == NULL))  
  11.         throw std::range_error("pointer unavailable");  
  12.   
  13.     for (Type *outer = begin+2; outer < end; ++outer)  
  14.     {  
  15.         *begin = *outer;  
  16.         Type *inner = outer;  
  17.   
  18.         //因为*begin不可能 > *begin, 所以该循环一定会退出  
  19.         while (*(inner-1) > *begin)  
  20.         {  
  21.             *(inner) = *(inner-1);  
  22.             --inner;  
  23.         }  
  24.         *inner = *begin;  
  25.     }  
  26. }  

附-permutation与std::next_permutation测试代码

  1. int main()  
  2. {  
  3.     vector<char> str;  
  4.     for (char ch = 'a'; ch <= 'c'; ++ch)  
  5.         str.push_back(ch);  
  6.   
  7.     permutation(&(*str.begin()), 0, 2);  
  8.   
  9.     cout << "----------" << endl;  
  10.     typedef vector<char>::iterator Iter_type;  
  11.     do  
  12.     {  
  13.         for (Iter_type iter = str.begin(); iter != str.end(); ++iter)  
  14.             cout << *iter << ' ';  
  15.         cout << endl;  
  16.     }  
  17.     while (std::next_permutation(str.begin(), str.end()));  
  18.   
  19.     return 0;  



原文地址:http://blog.csdn.net/zjf280441589/article/details/42318211

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值