插入排序(InsertSort):

插入排序的基本思想:元素逐个遍历,在每次遍历的循环中,都要跟之前的元素做比较并“交换”元素,直到放在“合适的位置上”。

插入排序的特点:时间复杂度是随着待排数组的有序性变化的,数组越有序,插入排序的时间复杂度越低(接近O(n)级别),反之,时间复杂度越高(O(n*n)级别),平均情况是O(n*n)级别,所以我们日常使用时,只针对较为有序的数组进行插入排序,插入排序通常并不需要额外的数据存储空间,插入排序将数组分为无序区和有序区两个区,然后不断将无序区的第一个元素按大小顺序插入到有序区中去,最终将所有无序区元素都移动到有序区完成排序,所以插入排序通常是稳定的,但若将两层循环内部的判断条件加上等号,产生了“多余的”交换操作,此时插入排序又是不稳定的,不过没人会这样做;

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <string>
  4. #include <algorithm>
  5. #include "SortTestHelper.h"
  6.  
  7. template<typename T>
  8. void insertSort(T arr[], int n ){
  9.  
  10. for(int i = ; i < n-; i++){
  11. for(int j = i+; j > ; j--){
  12. if(arr[j] < arr[j-]){
  13. swap(arr[j-], arr[j]);
  14. }else{
  15. break;
  16. }
  17. }
  18. }
  19. }

插入排序的优化:

由于在元素遍历的过程中,“交换”元素的时间代价总比“判断”的时间代价要大(“交换”元素需要三次赋值,而“判断”只要一次),故可以在第一层循环遍历元素的时候,将元素缓存,并循环判断,知道遇到“合适的位置”:

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <string>
  4. #include <algorithm>
  5. #include "SortTestHelper.h"
  6.  
  7. template<typename T>
  8. void insertSort_Enhanced(T arr[], int n ){
  9.  
  10. for(int i = ; i < n-; i++){
  11.  
  12. T e = arr[i];
  13. int j;
  14. for(j = i; j > && arr[j-] > e; j-- ){
  15. arr[j] = arr[j-];
  16. }
  17. arr[j] = e;
  18. }
  19. }

归并排序(MergeSort):

归并排序的基本思想:基于分治策略(Divide and Conquer),将待排序序列R[0...n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2个长度为2的有序表;将这些有序序列再次归并,得到n/4个长度为4的有序序列;如此反复进行下去,最后得到一个长度为n的有序序列。

归并排序的特点:时间复杂度恒为O(nlogn)级别,归并排序是稳定的,但需要额外的存储空间(O(n)级别)。

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <string>
  4. #include <algorithm>
  5. #include "SortTestHelper.h"
  6.  
  7. //将arr[l..mid]和arr[mid+1...r]两部分进行归并
  8. template<typename T>
  9. void _merge(T arr[], int l, int mid, int r){
  10.  
  11. T *aux = new T[r-l+];
  12. int right = mid + ;
  13. int tmpIndex = ;
  14. int left = l;
  15.  
  16. //归并内部用插排把元素一个一个塞进辅助数组
  17. while(l <= mid && right <= r){
  18. if(arr[l] <= arr[right]){
  19. aux[ tmpIndex++ ] = arr[ l++ ];
  20. }else{
  21. aux[ tmpIndex++ ] = arr[ right++ ];
  22. }
  23. }
       //特殊对待一边已经遍历完,另一边还剩一组序列的元素
  24. if(left == mid+){
  25. while(right <= r)
  26. aux[ tmpIndex++ ] = arr[ right++ ];
  27. }else{
  28. while(l <= mid)
  29. aux[ tmpIndex++ ] = arr[ left++ ];
  30. }
  31. //再循环把辅助数组的元素覆盖进原数组
  32. for(left = l, tmpIndex = ;left <= r; left++, tmpIndex++)
  33. arr[left] = aux[tmpIndex];
  34.  
  35. //释放辅助数组的存储空间
  36. delete []aux;
  37. }
  38. template<typename T>
  39. void segment(T arr[], int l, int r ){
  40.    //递归方式首先就是写递归出口
  41. if( l >= r )
  42. return;
  43.  
  44. //解决l+r两个大整数相加会整数溢出的情况
  45. //int mid = (l+r)/2;
  46. int mid = (r-l)/+l;
  47.  
  48. segment(arr, l, mid);
  49. segment(arr, mid+, r);
  50. if( arr[mid] > arr[mid+] ) //优化归并排序,排除不必要的归并操作
  51. _merge(arr, l, mid, r);
  52. }
  53. template<typename T>
  54. void mergeSort(T arr[], int n ){
  55. segment(arr, , n-);
  56. }

以上是用递归方式自顶向下并初步优化了的归并排序实现代码,总体思路就是主程序从mergeSort函数调用归并排序,在segment函数中进行分治,分为几乎等长的两边分别进行递归,最后再调用_merge()进行当前递归层上的左右部分的归并,这里有个小优化,排除了当左边的序列的最大数小于等于右边数列的最小数时的情况,因为此时合并后已经是有序的了,归并内部实现就是利用辅助数组aux[](r-l+1长度的),因左右部分都是有序的,只要利用两个索引和一个辅助数组指针,依次分别遍历左右部分,判断元素大小,并逐个塞进辅助数组aux[]中,完成遍历之后将辅助数组aux[]内部排好序的序列覆盖原数组,并释放辅助数组的空间。

配上图辅助理解(红笔为程序执行顺序,红线下行为进入函数,上行为返回上层递归)配图来源

几种常用排序算法代码实现和基本优化(持续更新ing..)的更多相关文章

  1. 用 Java 实现的八种常用排序算法

    八种排序算法可以按照如图分类 交换排序 所谓交换,就是序列中任意两个元素进行比较,根据比较结果来交换各自在序列中的位置,以此达到排序的目的. 1. 冒泡排序 冒泡排序是一种简单的交换排序算法,以升序排 ...

  2. 几种常用排序算法的python实现

    1:快速排序 思想: 任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序. 一趟快速排序的算法是: 1)设置 ...

  3. Java种八种常用排序算法

    1 直接插入排序 经常碰到这样一类排序问题:把新的数据插入到已经排好的数据列中. 将第一个数和第二个数排序,然后构成一个有序序列 将第三个数插入进去,构成一个新的有序序列. 对第四个数.第五个数……直 ...

  4. 面试中常用排序算法实现(Java)

    当我们进行数据处理的时候,往往需要对数据进行查找操作,一个有序的数据集往往能够在高效的查找算法下快速得到结果.所以排序的效率就会显的十分重要,本篇我们将着重的介绍几个常见的排序算法,涉及如下内容: 排 ...

  5. 转载部长一篇大作:常用排序算法之JavaScript实现

    转载部长一篇大作:常用排序算法之JavaScript实现 注:本文是转载实验室同门王部长的大作,找实习找工作在即,本文颇有用处!原文出处:http://www.cnblogs.com/ywang172 ...

  6. 常用排序算法的python实现和性能分析

    常用排序算法的python实现和性能分析 一年一度的换工作高峰又到了,HR大概每天都塞几份简历过来,基本上一天安排两个面试的话,当天就只能加班干活了.趁着面试别人的机会,自己也把一些基础算法和一些面试 ...

  7. 常用排序算法java实现

    写在前面:纸上得来终觉浅.基本排序算法的思想,可能很多人都说的头头是到,但能说和能写出来,真的还是有很大区别的. 今天整理了一下各种常用排序算法,当然还不全,后面会继续补充.代码中可能有累赘或错误的地 ...

  8. 我们一起来排序——使用Java语言优雅地实现常用排序算法

    破阵子·春景 燕子来时新社,梨花落后清明. 池上碧苔三四点,叶底黄鹂一两声.日长飞絮轻. 巧笑同桌伙伴,上学径里逢迎. 疑怪昨宵春梦好,元是今朝Offer拿.笑从双脸生. 排序算法--最基础的算法,互 ...

  9. Python实现常用排序算法

    Python实现常用排序算法 冒泡排序 思路: 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完 ...

随机推荐

  1. js动态加载activeX控件在IE11与低版本IE中的差异

    由于IE11更加遵循W3C规范,所以IE11与低版本IE在加载activeX时有差别. 1.IE11中动态加载activeX的顺序 var objectTag = document.createEle ...

  2. 选中DataGrid的Cell而不是row

    主要是针对DataGridCellsPresenter而不是SelectiveScrollingGrid,使用时DataGridRow应用这个style就可以了. <Style x:Key=&q ...

  3. H+ Se7en WebUI

    http://www.zi-han.net/theme/hplus/webim.html

  4. day1 java基础

    常见的dos命令 盘符: 进入指定的盘符下. dir : 列出当前目录下的文件以及文件夹 md : 创建目录 rd : 删除目录    注意:rd不能删除非空的文件夹,而且只能用于删除文件夹. cd ...

  5. 使用go实现基于命令行的计算器程序

    项目目录结构 calcs.go源文件 package main import ( "fmt" "os" "strconv" "my ...

  6. jquery、javascript实现(get、post两种方式)跨域解决方法

    一.实现get方式跨域请求数据 浏览器端 <script> $(document).ready(function(){ $.ajax({ url: "http://www.xxx ...

  7. dialog 设置maxHeight 最大高度

    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);Displ ...

  8. 在UI程序设计中使用BackgroundWorker进行多线程异步处

    WinForm的应用程序中如果执行了一个的非常冗长的处理操作,(比如文件检索,大运算量计算),在执行时就会锁定用户界面,虽然主活动窗口还在运行,但用户无法与程序交互,无法移动窗体或改变窗体大小,导致程 ...

  9. Linux之用户和用户组简析

    学习网址:http://c.biancheng.net/linux_tutorial/60/

  10. Unity 自动寻路Navmesh之跳跃,攀爬,斜坡

    在之前的几篇Blog总,我们已经系统学习了自动寻路插件Navmesh的相关概念和细节.然而,如果要做一个场景精美的手游,需要用到各种复杂的场景地形,而不仅仅是平地上的自动寻路.今天我们将通过一个完整的 ...