排序算法合集
来源:互联网 发布:在线教育数据分析 编辑:程序博客网 时间:2024/04/28 06:13
排序算法有很多中,我在这里只能粗略地介绍其中的6种,有什么不当之处还望读者多多指教。
为了方便起见,在这里假设排序为升序排列,用C++实现。
选择排序
选择排序是较为简单的一种排序方式,特点是在当前所指的元素前找比当前元素小的元素,如果找到就交换位置,是一种不稳定的排序方式,平均时间复杂度为O(n^2)。
具体实现:
for (int i = 1; i < n; i++) {//设定list[i]为被指向的数 for (int j = 0; j < i; j++) {//查找到被指向的元素为止 if (list[i] < list[j])//若后面的数比前面小,则交换位置 Swap(list[i], list[j]); }}
冒泡排序
冒泡排序也是一种较为简单的排序方式,特点是用每次用相邻两个元素比较,大的放在后面,然后右移指针。每一次可以选出一个最大的放在最后。这是一种稳定的排序方式,平均时间复杂度为O(n^2)。
优化思路:如果检测到序列已经排好序了,就不需要再次进行循环了,而是可以直接跳出。可以通过增加一个bool值来描述是否已经排好序。
但是,就算已经排好序,也需要经过一轮检测来得知是排好序的,所以无论如何都会经过一次遍历。
具体实现:
bool sorted = true;//先假设是排好序的for (int i = n-1; i >=0 ; i--) {//要排序的元素数递减 for (int j = 0; j < i; j++) { if (list[j] > list[j + 1]) { //当一趟里前面的元素比后面的元素大时,交换 Swap(list[j], list[j + 1]); sorted = false;//这时认为没有排好序 } } if (sorted) break;//如果已经排好序,跳出}
插入排序
插入排序的特点是每次取一个元素插入之前已经排好序的序列中,如果前面的元素比较大,就后移一位,直到找到比要插入的元素小的元素或找到数组0号元素为止。第一次插入时将第一个元素自身视为有序序列。这是一种稳定的排序方式,平均时间复杂度为O(n^2)。
具体实现:
for (int i = 1; i < n; i++) { int temp = a[i];//将当前元素存到临时元素中 int ti = i;//将当前位置也保存到临时位置 while (ti > 0 && a[ti - 1] > temp) a[ti] = a[ti-- - 1];//当数组中元素比要插入的元素大时,后移一位 a[ti] = temp;//在满足条件的位置插入临时元素}
基数排序
基数排序的特点是设置一个基数(假设为10),然后创建10个桶,每个桶最多有n(元素总个数)个元素,然后通过取模来按照余数的大小进行排序,先对个位排序,并把排序后的元素放回原数组中,再对十位排序……直到所有位都排序结束后,原数组就变为了有序数组。
这种排序方式是稳定的,平均时间复杂度是O(d(r+n)),其中r代表基数,d代表长度(共有几位),n代表元素个数。
具体实现:
T* bins[10];//10个桶 int p[10] = { 0 };//每个桶中放入了几个数 bool next = true;//是否要进行下一轮 int digit = 1;//每轮的位数 int remainder = 0;//每次的余数 for (int i = 0; i < 10; i++) {//初始化 bins[i] = new T[n]; } do { for (int i = 0; i < n; i++) {//把元素放入桶中 remainder = list[i] % (digit*10) / digit; //当还有任意元素有余数时,循环要继续 if (remainder) next = true; else next = false; bins[remainder][p[remainder]++] = list[i]; //将元素放到余数桶的最后一个数的后面 } int k = 0;//放置元素的位置 for (int i = 0; i < 10; i++) { for (int j = 0; j < p[i]; j++) { //把每个桶中的元素重新装到list中 list[k++] = bins[i][j]; } } for (int i = 0; i < 10; i++) //重置桶中放入的元素数 p[i] = 0; digit *= 10; } while (next); for (int i = 0; i < 10; i++) {//释放空间 delete [] bins[i]; }
- 归并排序
归并排序是一种较为复杂的排序方法,特点是分而治之,将原数组先分成一个个小数组,再对每个小数组进行归并,形成一个排好序的大数组,再下一步归并,直到原数组整个被排好序为止。这是一种稳定的排序方式,时间复杂度为O(nlogn),需要一个存放临时数据的数组。我以前写过递归实现的伪代码,这里就再写一个非递归实现的代码吧。
具体实现:
template<class T>void Merge(T* c, T* d, int l, int m, int r){ int i = l, //第一个块的指针 j = m + 1, //第二个块的指针 k = l; //结果的指针 //把小的先放进去,直到有一个块放完 while ((i <= m) && (j <= r)) { if (c[i] < c[j]) d[k++] = c[i++]; else d[k++] = c[j++]; } //把还没有放完的数据放进d数组 if (i > m) for (int q = j; q <= r; q++) d[k++] = c[q]; else for (int q = i; q <= m; q++) d[k++] = c[q];}template<class T>void MergePass(T* a, T* b, int s, int n){ int i = 0;//从头开始进行 while (i <= n - 2 * s) {//能够分出长度为s的两段时,直接对两段归并 Merge(a, b, i, i + s - 1, i + 2 * s - 1); i = i + 2 * s; //在数组中后移两个段的距离 } //不能分成恰好的两段时,有两种情况: //如果能分成两段,则分成一段长度为s的,一段包含剩下元素的,进行归并; //不能分成两段,则直接拷贝到b数组中 if (i + s < n) Merge(a, b, i, i + s - 1, n - 1); else for (int j = i; j <= n - 1; j++) b[j] = a[j];}template<class T>void MergeSort(T * a, int n){ T* b = new T[n]; //存放过程中数据的数组 int s = 1; //段长度 while (s < n) { MergePass(a, b, s, n);//从a到b归并 s += s; //长度加倍 MergePass(b, a, s, n);//从b到a归并 s += s; } delete[] b;}
快速排序
快速排序是一种较复杂的排序方式,但是性能十分优秀。它的特点是取一个数作为参照数,从左找比该数大的数,找到后再从右找比该数小的数,如果找到了这样一对数,就将它们交换位置,直到左边指针大于等于右边指针,这时把参照数和右指针指着的数交换位置,然后对该位置左边的数据和右边的数据分别进行归并排序,直到进入方法时的左指针就大于等于右指针时,直接返回。这是一种不稳定的排序方式,最坏时间复杂度为O(n^2),在数组本身就有序时出现,平均时间复杂度为O(nlogn)。
具体实现:
template<class T>void quickSort(T* a, int left, int right,int n){ //当左指针大于等于右指针时,不需要排序,直接返回 if (left >= right) return; int i = left, //从左到右的指针 j = right + 1; //从右到左的指针 T pivot = a[left]; //参照数 while (true) {//从左找大于参照数的数,从右找小于参照数的数 do { i++; } while (a[i] < pivot);//小于参照数,继续查找下一个 do { j--; } while (a[j] > pivot);//大于参照数,继续查找下一个 if (i >= j) break; //找不到要交换的对 Swap(a[i], a[j]); } //参照数与右指针所指的数交换位置 a[left] = a[j]; a[j] = pivot; quickSort(a, left, j - 1,n);//对左半边排序 quickSort(a, j + 1, right,n);//对右半边排序}
这样6个排序算法就大致讲完了,如果有什么错误与不足还望指正。
- 排序算法合集
- 排序算法合集
- 排序算法合集
- 排序算法合集
- 排序算法合集
- 排序算法合集
- 排序算法合集
- 经典排序算法合集
- 排序算法合集(Java)
- 史上最强排序算法合集
- C++实现排序算法合集
- 排序合集
- 排序问题合集
- 排序合集
- 遗传算法合集
- c# 算法合集
- 算法合集
- js算法合集
- 在Windows 客户端下备份远程L…
- ora-01110,ora-01109删除表空间文…
- oracle删除用户和表空间
- rocketMq配置安装
- Android的回调
- 排序算法合集
- 感觉要开始准备找工作的事情了,否则毕业了还是以前的问题,不能眼高
- 酷爱编程的人是怎么度过元旦呢?
- SurfaceView学习
- 添加用户到sudoers
- 理论: 图论(4): 单源最短路径概述
- Paint---ColorFilter
- 我的Vim备忘录(2)
- Maven学习系列--06测试