1.1、冒泡排序
原理
从数组中(从下标较小的元素开始),依次对相邻两个元素的值进行两两比较,若发现复合交换规则就进行交换,使对应的元素逐渐从前移向后部,就如果水底下的气泡一样逐渐向上冒
排序规则
-
一共进行数组长度-1次循环
-
每一趟排序的次数在减少(减去已经排好的数据)并且每一趟比较的次数最长为数组长度-1次
**实现思路:**定义嵌套循环,外层循环控制循环的次数(趟数),内层循环控制每一趟的比较次数,每一趟比较都会确定一个数,所以每一趟的比较次数都会减少一次
cpp
// 一共进行数组长度-1次循环
for(int i = 0; i < 数组长度-1; i++){
// 每一趟的循环
for(int j = 0; j < 数组长度-1-i; j++){
交换数据代码实现逻辑
}
}
优化
- 在某趟排序中没有数据的交换,也就是数据没有发生变动,就可以提前结束
**实现思路:**定义一个变量进行表示,如果发生数据的交换,就更改变量的值,最后判断这个变量是否发生改变从而提前结束循环
cpp
// 一共进行数组长度-1次循环
for(int i = 0; i < 数组长度-1; i++){
// 每一趟的循环
for(int j = 0; j < 数组长度-1-i; j++){
交换数据代码实现逻辑
}
这里进行判断变量的值,如果没有发生变化就退出循环
}
1.2、选择排序
原理
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
排序规则
-
一共进行数组长度-1轮排序
-
每一轮排序的次数都在减少(减去已经排好的数据)并且每一轮比较的次数最长为数组长度-1次
**实现思路:**先假定当前的这个数为最小数(或最大数)然后和后面的每一个数进行比较,如果发现比当前数更小(更大)的数,就重新确定最小的数,直到遍历到数组最后,获取到本轮最小数,在进行交换
cpp
for(int i = 0; i < 数组长度-1; i++){
定义最小值 = 数组名[i];
for(int j = i+1; j < 数组长度; j++){
if(min > 数组名[j]){
交换得到最小数
}
}
if(最小数 != 数组名[i]){
排序交换数据
}
}
例如:
cpp
#include <iostream>
using namespace std;
int main() {
// 定义一个数组
int arr[] = {12,3,1,5};
// 外层循环控制轮数
for(int i = 0; i < sizeof(arr)/ sizeof(int) - 1; i++){
// 设置最小值为第一个数
int min = arr[i];
// 内层循环控制每一轮对比次数--找出每一轮中的最小数
for(int j = i+1; j < sizeof(arr)/ sizeof(int) ; j++){
if(min < arr[j]){
swap(min,arr[j]);
}
}
// 将最小数放到最前面
if(min != arr[i]){
swap(min ,arr[i]);
}
}
// 遍历
for (int a:arr) {
cout << a;
}
return 0;
}
1.3、插入排序
也是一种最简单的排序方法,其基本操作是将一条记录插入到已排好的有序表中,从而得到一个新的、记录数量增1的有序表
原理
插入排序的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
排序规则
-
① 从第一个元素开始,该元素可以认为已经被排序
-
② 取出下一个元素,在已经排序的元素序列中从后向前扫描
-
③如果该元素(已排序)大于新元素,将该元素移到下一位置
-
④ 重复步骤③,直到找到已排序的元素小于或者等于新元素的位置
-
⑤将新元素插入到该位置后
-
⑥ 重复步骤②~⑤
例如:
cpp
// 插入排序
void InsertSort(int arr[], int len){
// 检查数据合法性
if(arr == NULL || len <= 0){
return;
}
for(int i = 1; i < len; i++){
int tmp = arr[i];
int j;
for(j = i-1; j >= 0; j--){
//如果比tmp大把值往后移动一位
if(arr[j] > tmp){
arr[j+1] = arr[j];
}
else{
break;
}
}
arr[j+1] = tmp;
}
}
优化
直接插入排序每次往前插入时,是按顺序依次往前查找,数据量较大时,必然比较耗时,效率低。
改进思路: 在往前找合适的插入位置时采用二分查找的方式,即折半插入。
① 从第一个元素开始,该元素可以认为已经被排序 ② 取出下一个元素,在已经排序的元素序列中二分查找到第一个比它大的数的位置 ③将新元素插入到该位置后 ④ 重复上述两步
改进代码:
cpp
// 插入排序改进:二分插入排序
void BinaryInsertSort(int arr[], int len)
{
int key, left, right, middle;
for (int i=1; i<len; i++)
{
key = a[i];
left = 0;
right = i-1;
while (left<=right)
{
middle = (left+right)/2;
if (a[middle]>key)
right = middle-1;
else
left = middle+1;
}
for(int j=i-1; j>=left; j--)
{
a[j+1] = a[j];
}
a[left] = key;
}
}
1.4、快速排序
快速排序算法是对冒泡排序算法的一种改进算法,在当前所有内部排序算法中,快速排序算法被认为是最好的排序算法之一。
思想
通过一趟排序将待排序的序列分割为左右两个子序列,左边的子序列中所有数据都比右边子序列中的数据小,然后对左右两个子序列继续进行排序,直到整个序列有序。
原理
对于要排序的数组,首先任意选取一个数据(通常为首元素)作为关键数据,将序列中所有比该元素小的元素都放到它的左边,将所有比它大的元素都放到它的右边,再对左右两边分别用同样的方法直到每一个待处理的序列长度为1,排序结束
例如:
cpp
#include<iostream>
using namespace std;
void QuickSort(int a[],int low,int high)
{
if(low>=high) return;//此时已经完成排序,直接返回
int i = low;
int j = high;
int key = a[low];
while(i<j)//实现第一趟排序
{
while(i<j&&key<a[j]) j--;//从右向左找比key小的值
a[i] = a[j];
while(i<j&&key>a[i]) i++;//从左向右找比key大的值
a[j] = a[i];
}
a[i] = key;//将关键数据填入low=high的位置
QuickSort(a,low,i-1);//左边子序列递归排序
QuickSort(a,i+1,high);//右边子序列递归排序
}
int main()
{
int a[] = {3,5,8,2,9,1};
int num = 6;
QuickSort(a,0,num-1);
for(int i = 0;i<num;i++)
cout<<a[i]<<" ";//输出1 2 3 5 8 9
return 0;
}
1.5、合并排序
思想
归并排序是用分治思想,分治模式在每一层递归上有三个步骤:
-
分解(Divide):将n个元素分成个含n/2个元素的子序列。
-
解决(Conquer):用合并排序法对两个子序列递归的排序。
-
合并(Combine):合并两个已排序的子序列已得到排序结果。
实现逻辑
1 迭代法
-
① 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
-
② 设定两个指针,最初位置分别为两个已经排序序列的起始位置
-
③ 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
-
④ 重复步骤③直到某一指针到达序列尾
-
⑤ 将另一序列剩下的所有元素直接复制到合并序列尾
2 递归法
-
① 将序列每相邻两个数字进行归并操作,形成floor(n/2)个序列,排序后每个序列包含两个元素
-
② 将上述序列再次归并,形成floor(n/4)个序列,每个序列包含四个元素
-
③ 重复步骤②,直到所有元素排序完毕
代码实现:
迭代法:
cpp
// 归并排序
template<typename T>
void merge_sort(T arr[], int len) {
T* a = arr;
T* b = new T[len];
for (int seg = 1; seg < len; seg += seg) {
for (int start = 0; start < len; start += seg + seg) {
int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
int k = low;
int start1 = low, end1 = mid;
int start2 = mid, end2 = high;
while (start1 < end1 && start2 < end2)
b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
while (start1 < end1)
b[k++] = a[start1++];
while (start2 < end2)
b[k++] = a[start2++];
}
T* temp = a;
a = b;
b = temp;
}
if (a != arr) {
for (int i = 0; i < len; i++)
b[i] = a[i];
b = a;
}
delete[] b;
}
递归法:
cpp
// 归并排序
template<typename T>
void merge_sort_recursive(T arr[], T reg[], int start, int end) {
if (start >= end)
return;
int len = end - start, mid = (len >> 1) + start;
int start1 = start, end1 = mid;
int start2 = mid + 1, end2 = end;
merge_sort_recursive(arr, reg, start1, end1);
merge_sort_recursive(arr, reg, start2, end2);
int k = start;
while (start1 <= end1 && start2 <= end2)
reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
while (start1 <= end1)
reg[k++] = arr[start1++];
while (start2 <= end2)
reg[k++] = arr[start2++];
for (k = start; k <= end; k++)
arr[k] = reg[k];
}
// merge_sort
template<typename T>
void merge_sort(T arr[], const int len) {
T reg[len];
merge_sort_recursive(arr, reg, 0, len - 1);
}