排序——交换排序
来源:互联网 发布:java飞机大战扇形子弹 编辑:程序博客网 时间:2024/06/08 19:14
基本思想
两两比较待排序元素的大小,发现两个元素的次序相反时即进行交换,直到序列全部有序为止。
冒泡排序
1.排序思路
对无序区每两个相邻的元素进行比较,小元素换至大元素之后(之前),经过一趟排序后,最小的元素到达最后端(最前端)。接着,再在剩下的元素中重复上述过程。这样,通过无序区中相邻元素的比较和交换,可以使得最小的元素像如气泡一般逐渐往上“漂浮”。
2.排序算法
void BubbleSort(int *arr, int size){ if (arr == NULL) return; int i, j; for (i = 0; i < size-1; i++) { //正序 /*for (j = size - 1; j > i; j--) { if (arr[j] < arr[j - 1]) { int tmp = arr[j]; arr[j] = arr[j - 1]; arr[j - 1] = tmp; } }*/ //逆序 for (j = 0; j < size - 1 - i; j++) { if (arr[j] < arr[j + 1]) { int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; } } }}
3.算法分析
当初始数据为正序时,一趟扫描即可完成排序,此时最好时间复杂度为O(N);当初始数据为逆序时,则需要进行n-1趟排序,且每趟排序要进行n-i-1次比较,每次比较都会交换元素,此时最坏时间复杂度为O(N^2)。
故,冒泡排序的时间复杂度为O(N^2),空间复杂度为O(1)。虽然冒泡排序不一定要进行n-1趟,但它的元素移动次数较多,所以平均时间性能比直接插入排序要差。
冒泡排序是一种稳定的排序算法。
4.算法优化
当某趟排序之后,序列已经完全有序时,大可不必继续排序,于是我们设置一个标志为flag,在每趟排序的开始重置flag,若该趟排序结束时,flag没有变化,则证明序列已经有序,即可break退出循环。
void BubbleSort1(int *arr, int size){ if (arr == NULL) return; int i, j, flag; for (i = 0; i < size - 1; i++) { flag = 1; for (j = size - 1; j>i; j--) { if (arr[j] < arr[j - 1]) { int tmp = arr[j]; arr[j] = arr[j - 1]; arr[j - 1] = tmp; flag = 0; } } if (flag == 1) //说明此趟排序没有进入内循环,已经有序 { break; } }}
快速排序
1.排序思路
在待排序的n个元素中任取一个元素作为基准,数据序列被此元素划分成两部分,比该元素小的所有元素放在前边部分,比该元素大的所有元素放在后边部分,并把该元素排在这两部分的中间。这个过程称为一趟快速排序,之后对划分出来的两部分分别重复上述过程,直至每部分内只有一个或没有元素为止。
2.排序算法
//1.左右指针法int _PartSort1(int *arr, int begin, int end){ int key = arr[end]; int left = begin; int right = end; while (left < right) { while (left < right && arr[left] <= key) { left++; } while (left < right&&arr[right] >= key) { right--; } swap(arr[left], arr[right]); } swap(arr[left], arr[end]); return left;}//2.挖坑法int _PartSort2(int *arr, int begin, int end){ int key = arr[end]; while (begin < end) { while (begin < end && arr[begin] <= key) { begin++; } arr[end] = arr[begin]; //end当坑 while (begin < end && arr[end] >= key) { end--; } arr[begin] = arr[end]; //begin当坑 } arr[begin] = key; return begin;}//2.前后指针法int _PartSort3(int *arr, int begin, int end){ int prev = begin; int cur = begin+1; while (cur <= end) { if (arr[cur] <= arr[begin]) { prev++; if (prev != cur) { swap(arr[prev], arr[cur]); } cur++; } else { cur++; } } swap(arr[prev], arr[begin]); return prev;}void Quick(int *arr, int begin, int end){ if (arr == NULL) return; if (begin < end) { //int div = _PartSort1(arr, begin, end); //int div = _PartSort2(arr, begin, end); int div = _PartSort3(arr, begin, end); Quick(arr, begin, div - 1); Quick(arr, div + 1, end); }}
3.算法分析
快速排序的时间主要耗费在划分操作上,当初始数据递增有序或递减有序,且每次的划分基准都取最小值或最大值时,则快速排序所需的比较次数最多,最坏时间复杂度为O(N^2)。在最好情况下,每次划分基准值都取当前无序区的中值时,划分的左右两个子序列的长度大致相等,此时的时间复杂度可用递归树来分析,递归树的高度为lgN,而递归树每一层所需要的比较次数不超过N次,则整个排序过程的总比较次数为N*lgN,故最好时间复杂度为O(N*lgN)。
注意,快速排序的时间复杂度不看最坏情况!故快速排序的时间复杂度为O(N*lgN)。递归平均所需的栈空间为lgN,故快速排序的空间复杂度为O(lgN)。快速排序是一种不稳定的排序算法。
4.算法优化
三数取中法:为了防止所选划分基准值为序列最大值或最小值,用三数取中法来确定基准值,提高算法效率。
int GetMidIndex(int *a, int begin, int end){ int mid = begin + ((end - begin) >> 1); if (a[begin] < a[mid]) { if (a[end] > a[mid]) { return mid; } else if (a[end] < a[begin]) { return begin; } else { return end; } } else //a[begin] >= a[mid] { if (a[end] < a[mid]) { return mid; } else if (a[end] > a[begin]) { return begin; } else { return end; } }}
小区间划分:优化递归的层数,对接近有序的情况不再递归,使用插入排序。
void QuickSort(int *arr, int begin, int end){ if (arr == NULL) return; if (begin < end) { if (end - begin > 10) { int div = _PartSort1(arr, begin, end); QuickSort(arr, begin, div - 1); QuickSort(arr, div + 1, end); } else { InsertSort(arr + begin, end - begin + 1); } }}
快速排序的非递归实现
1.排序思路
把递归问题转换为非递归问题,可以借助栈来实现,我们可以把每个子区间的begin和end保存在栈中,然后成对取出,对子区间排序,接着又把划分出来的子区间的begin和end保存在栈中,重复上述过程,直至子区间的元素只剩下一个或为空。
2.排序算法
oid QuickSortNonR(int *arr, int begin, int end){ if (arr == NULL) return; int left, right; stack<int> s; s.push(begin); s.push(end); while (!s.empty()) { right = s.top(); s.pop(); left = s.top(); s.pop(); if (left < right) { int div = _Part1(arr, left, right); //前部分子区间 s.push(left); s.push(div - 1); //后部分子区间 s.push(div + 1); s.push(right); } }}
- 排序——交换排序
- 排序——交换排序
- 交换排序—快速排序
- 交换排序——冒泡排序
- 交换排序——冒泡排序
- 交换排序——快速排序
- 6.交换排序——冒泡排序
- 7.交换排序——快速排序
- 交换类排序——冒泡排序
- 起泡排序——交换排序
- 排序算法——交换排序
- 交换排序——冒泡排序
- 交换排序——快速排序
- 排序算法浅析——交换排序
- 交换排序——冒泡排序
- 排序算法——交换类排序
- 排序算法——交换排序
- 交换排序——冒泡排序
- OpenCV—形态学运算定义与实现
- 原生android工程实现RN集成
- stl 常见问题
- 动态规划的一些笔记
- JavaScript中的this
- 排序——交换排序
- 阿里巴巴Java开发手册
- uubuntu 常见的操作命令
- 网络编程中(socket)用户登录验证以及注册(单用户)
- lua调用c++
- 比特币现金BCC的出现带来了这些套利机会
- BZOJ 3771 Triple
- java重载与覆盖的区别以及java多态实现的机制
- 51Nod-1969-Fire!