一、冒泡排序
思路
通过相邻元素之间的比较和交换,使得每一轮比较后,最大(或最小)的元素能够“浮”到数列的一端。
步骤
- 比较相邻的两个元素,如果它们的顺序错误(即前一个元素大于后一个元素,假设是升序排序),则交换这两个元素的位置。
- 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
代码
void bubble_sort(int arr[],int len)
{
for(int i = 0; i < len - 1; i++) // 外部循环 表示趟数
{
for(int j = 0; j < len - 1 -i; j++) // 内部循环 每一轮遍历交换最大值
{
if(arr[j] > arr[j+1]) // >:升序 <:降序
{
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = arr[j];
}
}
}
}
优化
特殊情况
arr[] = {1,2,3,4,5,6,7,8,10,9};
思路
在交换的地方加一个标记 flag,如果经过一趟排序没有交换元素,说明这组数据已经有序,不用再继续下去。
代码
void bubble_sort(int arr[],int len)
{
for(int i = 0; i < len - 1; i++)
{
int flag = 0; // 排序标志
for(int j = 0; j < len - 1 -i; j++)
{
if(arr[j] > arr[j+1])
{
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = arr[j];
flag = 1; // 排序标志改变
}
}
if(flag == 0) // 标志没改变已经有序
{
return;
}
}
}
二、选择排序
思路
基于每次从未排序部分选择最小(或最大)的元素,然后将其放到已排序部分的末尾(或开头)。
步骤
-
初始化:首先,将待排序的序列分为已排序部分和未排序部分。通常,已排序部分初始时为空,未排序部分包含整个序列。
-
选择最小(或最大)元素:从未排序部分中找出最小(或最大)的元素。这通常通过遍历未排序部分的每个元素来实现,并记录下最小(或最大)元素的索引。
-
交换位置:将找到的最小(或最大)元素与未排序部分的第一个元素交换位置。这样,最小(或最大)元素就被放到了已排序部分的末尾(或开头)。
-
缩小未排序部分:将已排序部分的最后一个元素(即刚刚交换过来的元素)之后的元素视为新的未排序部分,重复步骤2和3,直到未排序部分为空,即整个序列都排好序。
代码
void selection_sort(int arr[], int len)
{
for(int i = 0; i < len - 1; i++)
{
int min = i;
for(int j = i + 1; j < len; j++)
{
if(arr[j] < arr[min]) // <:升序 >:降序
{
min = j;
}
}
int temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
}
}
三、快速排序
思路
基于分治法的思想。分治法,字面解释为“分而治之”。
- 分:将问题分解为规模更小的子问题。这些子问题可以互相独立,且与原问题的形式相同。
- 治:递归地解决这些子问题。如果子问题的规模足够小,可以直接求解。
- 合:将已解决的子问题的解合并,得到原问题的解。
步骤
-
选择一个基准元素:从待排序的序列中随机选择一个元素作为基准(pivot),一般可以选择序列的第一个元素、最后一个元素或者中间元素,甚至可以通过一定的策略(如三数取中法)来选择一个更为合适的基准。
-
划分序列:将序列中小于基准的元素放在基准的左边,大于基准的元素放在基准的右边。经过这一步,基准元素就处于其最终排序位置。这个过程称为划分操作(partition)。
-
递归排序子序列:对基准左边和右边的两个子序列,递归地执行快速排序。即分别对两个子序列重复上述的基准选择和划分操作,直到整个序列有序。
代码
void quick_sort(int arr[], int start, int end) //从小到大排序
{
if (start < end) // 传入的是数组下标
{
int base = arr[start]; // 基准数base
int left = start;
int right = end;
while (left < right)
{
while (left < right && arr[right] >= base) // 从右向左找比基准数base大继续往下找
{
right--;
}
// 比基准数base小用right替换left即右边都是比基准数base大的数
arr[left] = arr[right];
while (left < right && arr[left] <= base) // 从左向右找比基准数base小继续往下找
{
left++;
}
// 比基准数base大用left替换right即左边都是比基准数base小的数
arr[right] = arr[left];
}
arr[left] = base; // right = left 此时该位置用base替换
// 递归余下的两个区域
quick_sort(arr, start, left - 1);
quick_sort(arr, left + 1, end);
}
}