排序上

排序上

交换类排序

基本思想:所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

冒泡排序

冒泡排序的特性总结:

  1. 冒泡排序是一种非常容易理解的排序
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)
  4. 稳定性:稳定

代码实现

void BublleSort(int*array, int size)
{for (int i = 0; i < size - 1; ++i)       //总共冒泡的趟数{//冒泡的方式----->用相邻元素进行比较for (int j = 0; j < size - i - 1; ++j)     //一次冒泡{if (array[j]>array[j + 1])Swap(&array[j], &array[j + 1]);}}
}

冒泡排序优化

void BublleSort(int*array, int size)
{   for (int i = 0; i < size - 1; ++i)       //总共冒泡的趟数{int IsChange = 0;         //查看这一趟有没有交换//冒泡的方式----->用相邻元素进行比较for (int j = 0; j < size - i - 1; ++j)       //一次冒泡{if (array[j]>array[j + 1]){Swap(&array[j], &array[j + 1]);IsChange = 1;}   }if (!IsChange)  //如果没有交换return;}
}

快速排序

一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

快速排序的特性总结:
  1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
  2. 时间复杂度:O(N*logN),最差场景,单支树O(N2)
  3. 空间复杂度:O(logN)
  4. 稳定性:不稳定
  5. 快排参考链接

代码实现

int Partion(int*array, int left, int right)
{//划分基准值
}
void QuickSort(int *array, int left, int right)
{if (right - left > 1){int div = Partion(array, left, right);QuickSort(array, left, div);QuickSort(array, div + 1, right);}
}

划分基准值的方式

  1. hoare版本
int Partion(int*array, int left, int right)
{int key = array[right - 1];int begin = left;int end = right - 1;while (begin<end){//从前往后找比基准值大的元素,找到就停下来,等于也往前走,因为找的是大的while (begin < end&&array[begin] <= key)begin++;//end从后往前找比基准值小的元素,找到就停下来,等于也往前走,找的是小的,不是等于while (begin < end&&array[end] >= key)end--;if (begin < end)Swap(&array[begin], &array[end]);}if (begin != right - 1)Swap(&array[begin], &array[right-1]);return begin;
}
  1. 挖坑法
int Partion2(int*array, int left, int right)
{int key = array[right - 1];int begin = left;int end = right - 1;while (begin<end){while (begin<end&&array[begin] <= key)begin++;if (begin<end){//上一个坑是end,begin是比基准值大的数array[end] = array[begin];end--;}while (begin<end&&array[end] >= key)end--;if (begin<end){//上次坑是end,填坑的是begin,填完坑后,begin成坑,由新end比基准值小的数来填array[begin] = array[end];begin++;}}array[begin] = key;return begin;
}
  1. 前后指针版本
int Partion3(int*array, int left, int right)
{int key = array[right - 1];int cur = left;int pre = cur - 1;while (cur<right){if (array[cur] < key && ++pre != cur)Swap(&array[cur], &array[pre]);cur++;}if (++pre != right - 1)Swap(&array[pre], &array[right - 1]);return pre;
}

快排的优化

  1. 三数取中法选key
  2. 递归到小的子区间时,可以考虑使用插入排序
三数取中法
//三数取中法
int GetMiddleIdx(int*array, int left, int right)
{int mid = left + ((right - left) >> 1);//left mid right-1if (array[left] < array[right - 1]){if (array[mid] < array[left])return left;else if (array[mid]>array[right - 1])return right - 1;elsereturn mid;}else{if (array[mid] > array[left])return left;else if (array[mid] < array[right - 1])return right - 1;elsereturn mid;}
}
int Partion(int*array, int left, int right)
{int middle = GetMiddleIdx(array, left, right);if (middle != right - 1)Swap(&array[middle], &array[right - 1]);int key = array[right - 1];int begin = left;int end = right - 1;while (begin<end){//从前往后找比基准值大的元素,找到就停下来,等于也往前走,因为找的是大的while (begin < end&&array[begin] <= key)begin++;//end从后往前找比基准值小的元素,找到就停下来,等于也往前走,找的是小的,不是等于while (begin < end&&array[end] >= key)end--;if (begin < end)Swap(&array[begin], &array[end]);}if (begin != right - 1)Swap(&array[begin], &array[right - 1]);return begin;
}
元素个数小用直接插入排序
void QuickSort(int *array, int left, int right)
{if (right - left < 16)//如果快排的元素个数没有达到16及其以上,就用插入排序InsertSort(array, right - left);else{int div = Partion(array, left, right);QuickSort(array, left, div);QuickSort(array, div + 1, right);}
}

快速排序非递归写法

#include"stack.h"
//快排非递归
void QuickSortNor(int*array, int size)
{int left = 0;int right = size;Stack s;StackInit(&s);StackPush(&s,right);StackPush(&s,left); //后进去的先出来,先出来的是左while (!StackEmpty(&s)){left = StackTop(&s);StackPop(&s);right = StackTop(&s);StackPop(&s);if (left < right){int div = Partion3(array, left, right);//先保存右半部分,先进后出来StackPush(&s,right);//右半部分右边界StackPush(&s, div + 1);//右半部分左边界//再保存左边部分,后进先出来StackPush(&s, div);//左半部分右边界StackPush(&s, left);//左半部分左边界}}StackDestroy(&s);
}

归并排序

归并排序

基本思想:

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

归并排序的特性总结:

  1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(N)
  4. 稳定性:稳定

代码实现

//归并到temp临时空间里
//两个有序序列合并成一个
void MergeData(int*array, int left, int mid, int right, int *temp)
{int begin1 = left, end1 = mid;int begin2 = mid, end2 = right;int index = left;while (begin1 < end1 && begin2 < end2)//第一个和第二个区间里的元素没有处理完{if (array[begin1] < array[begin2])temp[index++] = array[begin1++];elsetemp[index++] = array[begin2++];}//如果第一个空间里的数没有搬移完while (begin1 < end1)temp[index++] = array[begin1++];//第一个空间搬移完了,第二个空间里的元素没有搬移完while (begin2 < end2)temp[index++] = array[begin2++];
}
void _MergeSort(int*array, int left, int right,int*temp)
{//int*temp=(int*)malloc(sizeof(array[left])*(right-left));if (right - left>1) //区间里的元素超过一个,再排序{//找中间位置int mid = left + ((right - left) >> 1);_MergeSort(array, left, mid,temp);_MergeSort(array, mid, right,temp);MergeData(array, left, mid, right, temp);memcpy(array + left, temp + left, sizeof(array[left])*(right - left));}
}
void MergeSort(int *array, int size)
{int *temp = (int*)malloc(size*sizeof(array[0]));if (NULL == temp){assert(0);return;}_MergeSort(array, 0, size, temp);free(temp);
}

归并排序非递归

void MergeSortNor(int *array, int size)
{int *temp = (int*)malloc(size*sizeof(array[0]));if (NULL == temp){assert(0);return;}int gap = 1;while (gap < size){for (int i = 0; i < size; i += 2 * gap){int left = i;//左int mid = left + gap;//中int right = mid + gap;//右if (mid >= size)mid = size;if (right >= size)right = size;MergeData(array, left, mid, right, temp);}memcpy(array, temp, (sizeof(array[0])*size));gap *= 2;}free(temp);
}

非比较排序

思想:计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。


操作步骤:

  1. 统计相同元素出现次数
  2. 根据统计的结果将序列回收到原来的序列中

计数排序的特性总结:

  1. 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限
  2. 时间复杂度:O(MAX(N,范围))
  3. 空间复杂度:O(范围)
  4. 稳定性:稳定

代码实现

//场景:数据密集集中在某个范围中
void CountSort(int*array, int size)
{int minVal = array[0];//范围的左边界值int maxVal = array[0];//范围的右边界值//1--找数据的范围for (int i = 1; i < size; ++i){if (array[i] < minVal)minVal = array[i];if (array[i]>maxVal)maxVal = array[i];}//2--计算保存计数的空间int range = maxVal - minVal + 1;int *temp = (int*)malloc(sizeof(int)*range);if (NULL == temp){assert(0);return;}//3---空间位置里全部置为0memset(temp, 0, sizeof(int)*range);//memeset 按一个一个字节赋值,赋值0可以,赋值其他值不行,例如100,给一个字节赋值100//4--统计每个数据出现的次数for (int i = 0; i < size; ++i){temp[array[i] - minVal]++;}//5--回收数据int index = 0;for (int i = 0; i < range; ++i){while (temp[i]--)  //当前元素值不为0,说明该下标还有个数  {array[index++] = i + minVal;}}free(temp);
}

计数排序参考链接

排序总结

排序下---(冒泡排序,快速排序,快速排序优化,快速排序非递归,归并排序,计数排序)相关推荐

  1. 【好记性不如烂笔头】快速排序(三)非递归实现随机快排

    快速排序(三)非递归实现随机快排 前言

  2. 合并排序 非递归 java_合并排序-非递归

    #include //合并排序非递归--自然合并排序 typedef int Type; using namespace std; void Merge(Type c[],Type d[],int l ...

  3. 【八大排序详解~C语言版】直接插入排序-希尔排序- 直接选择排序-堆排序-冒泡排序-快速排序-归并排序-计数排序

    八大排序 1.直接插入排序 2.希尔排序 3.直接选择排序 直接选择排序改进 4.堆排序 1.建堆 2.利用堆删除思想来进行排序 5.冒泡排序 6.快速排序 递归实现 非递归实现 7.归并排序 递归实 ...

  4. 选择排序、冒泡排序、插入排序、快速排序、希尔排序、归并排序、堆排序和希尔排序的java实现比较

    几种排序实现代码 package com.delicacy.oatmeal.test.suanfa.sort;import java.util.Arrays; import java.util.Ran ...

  5. python实现冒泡排序算法的非递归版本_python排序算法速度比较:快速排序,归并排序,冒泡排序...

    前言 原理就不在这里说了,好多大神肯定比我这个初学者讲的好很多,推荐去B站看视频讲解,跟着手敲代码 为什么选这三个排序呢? 首先快排是必须掌握的 看看快排在最坏的情况下(O(n²)),且不使用辅助空间 ...

  6. Java中选择排序,冒泡排序,插入排序,快速排序

    一:冒泡法排序  //冒泡排序 注:从小到大排    //特点:效率低,实现简单   //思想:每一趟将待排序序列中最大元素移到最后,剩下的为新的待排序序列,重复上述步骤直到排完所有元素. 这只是冒泡 ...

  7. 经典排序算法----冒泡排序算法及其优化(稳定)

    冒泡排序(稳定) 冒泡排序就是把小的元素往前调或者把大的元素往后调.比较是相邻的两个元素比较,交换也发生在这两个元素之间.所以,如果两个元素相等,我想你是不会再无聊地把他们俩交换一下的:如果两个相等的 ...

  8. 非递归分治法排序 MergeSort without recursion

    一道作业题,网上没找到相关代码,就自己写了一个,比较有意思,经随机数10000规模测试通过. 关键在于合的时候找准"分点" void Merge(int L, int R, int ...

  9. 内部排序算法的实现(插入排序、选择排序、交换排序、归并排序、计数排序)

    目录 插入排序 直接插入排序 希尔排序 选择排序 直接选择排序 堆排序 交换排序 冒泡排序 快速排序(递归) 三数取中 快速排序(hoera版) 快速排序(挖坑版) 快速排序(前后指针版) 快速排序非 ...

最新文章

  1. php 的opcode缓存apc以及其安装
  2. 刻意练习:LeetCode实战 -- Task28.跳跃游戏
  3. Unity3d 开发-基础篇
  4. cocos2d-x 错误异常抛出捕获和崩溃拦截
  5. 7个杀手级的开源监测工具
  6. Spring框架你敢写精通,面试官就敢问@Autowired注解的实现原理
  7. ALV打印不显示打印界面的问题
  8. Qt的Socket通信
  9. php 删除某个文件夹,Php删除指定文件与文件夹的方法
  10. 禁用win10触摸屏手势_Win10平板边缘滑动手势大全及开启/关闭方法
  11. 在 Nginx 上支持 HTTP/3
  12. 警惕cocos2d-x Win32下资源命名大小写
  13. 桌面计算机安全策略,设置组策略实现Windows桌面显示计算机信息
  14. [五]java函数式编程归约reduce概念原理 stream reduce方法详解 reduce三个参数的reduce方法如何使用...
  15. JavaScript 插入元素到数组的方法汇总
  16. svg实现loading效果
  17. 2如何看表分区字段_技术分享|Oracle分区技术的实现总结
  18. 箭头函数的this指向谁_你好,我是 JavaScript 的 this
  19. Javascript 使用Qunit单元测试
  20. Android:ViewPage使用教程

热门文章

  1. 《Effective Java》读书笔记 Item 1:考虑静态工厂方法,而不是构造器
  2. windows下揪出java程序占用cpu很高的线程
  3. layer绑定回车事件(转)
  4. js中使用0 “” null undefined {}需要注意
  5. 工作总结:文件对话框的分类(C++)
  6. c#a服务器上传文件b服务器,C#_c#批量上传图片到服务器示例分享,客户端代码: 复制代码 代码 - phpStudy...
  7. python数字转换_Python实现中文数字转换为阿拉伯数字的方法示例
  8. php7如何安装swoole,PHP7如何安装Swoole?
  9. linux如何解除密码,如何在Linux下解除PDF文件的密码?
  10. seafile 部署_Seafile开启webdav及读写性能测试