目录
目录
一、冒泡排序
1.原理(思路):
(以升序为例)从左向右,每相邻的两个元素进行比较,每次比较之后,保证较大元素在较小元素的下一位,第一轮比较之后,所有值中的最大值会被放到最后一位,然后从头开始第二轮比较,就这样一轮一轮从左向右进行比较,最后就会得到由小到大排列的升序
2.代码实现:
#include <stdio.h>
void Bubble_sort(int arr[], int size)
{
int i, j, tmp;
for (i = 0; i < size - 1; i++)//size - 1是因为不用和自己比较,所以少比较一次
{
for (j = 0; j < size - 1 - i; j++)//size - 1 - i是因为每比较一轮就会排除最后一位
{
if (arr[j] > arr[j + 1])//排升序
{
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main()
{
int arr[10];
//输入十个整数
printf("输入十个整数:\n");
for (int i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);
}
//打印排序前的数组
printf("排序前:");
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
//冒泡排序
Bubble_sort(arr, 10);
printf("\n");
//打印排序后的数组
printf("排序后:");
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
2.1复杂度:
时间复杂度: 最坏情况为O(N^2),此时待排序列逆序
最好情况是O(N),此时待排序列为正序
空间复杂度:O(1)
2.2 稳定性:
稳定
3.运行结果:
二、插入排序
1.原理(思路):
(以升序为例)默认首元素已经有序,取下有序序列的下一位元素作为tmp,向前扫描有序序列,若tmp小于前一位的元素,则该元素后移一位,然后tmp继续与前面的元素比较,直到tmp大于前一位的元素,则插入该元素后面的下标位置,若tmp比全部有序序列的元素都要小,则直接插入到下标为零的位置,重复前面的步骤直到全部元素排列为升序
2.代码实现:
void Insert_sort(int* arr,int size)
{
for (int i = 0; i < size - 1; i++)//默认首元素有序,所以少一个数
{
int end = i;//记录有序序列最后一个元素的下标
int tmp = arr[end + 1];//将有序序列的下一位(待插入数据)作为tmp
while (end >= 0)//走一轮比较
{
if (tmp < arr[end])
{
arr[end + 1] = arr[end];
end--;
}
else
{
break;
}
}
arr[end + 1] = tmp;
}
}
int main()
{
int arr[10];
//输入十个整数
printf("输入十个整数:\n");
for (int i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);
}
//打印排序前的数组
printf("排序前:");
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
//插入排序
Insert_sort(arr, 10);
printf("\n");
//打印排序后的数组
printf("排序后:");
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
2.1复杂度:
时间复杂度: 最坏情况为O(N^2),此时待排序列逆序
空间复杂度:O(1)
2.2稳定性:
稳定
3.运行结果:
三、希尔排序
1.原理(思路):
1.首先进行预排序:(全部数据为n个,gap = n)第一轮开始,先gap = gap / 2,并将每两个相距为gap的数据为一组,进行插入排序,一轮结束后,再次将gap折半(gap = gap / 2)重复以上步骤
2.到最后一次排序时,gap = 1(为正常的插入排序),排序后得到有序排列
2.代码实现:
void Shell_sort(int* arr,int size)
{
int gap = size;
while (gap > 1)
{
gap = gap / 2;
for (int i = 0; i < size - gap; i++)
{
int end = i;
int tmp = arr[end + gap];
while (end >= 0)
{
if (tmp < arr[end])
{
arr[end + gap] = arr[end];
end -= gap;
}
else
{
break;
}
}
arr[end + gap] = tmp;
}
}
}
int main()
{
int arr[10];
//输入十个整数
printf("输入十个整数:\n");
for (int i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);
}
//打印排序前的数组
printf("排序前:");
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
//希尔排序
Shell_sort(arr, 10);
printf("\n");
//打印排序后的数组
printf("排序后:");
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
2.1复杂度
时间复杂度: 最坏情况为O(N^1.3)
最好情况为O(N)
空间复杂度:O(1)
2.2 稳定性:
不稳定
3.运行结果
四、选择排序
1.原理(思路):
每轮排序都要在无序序列里选出一个最小值,并将这个最小值与有序序列的下一位交换位置
改进思路:每轮排序都要在无序序列里选出一个最小值和一个最大值,分别放置在无序序列的第一位和最后一位
2.代码实现:
void swap(int* a,int* b)//排序中频繁使用交换,所以写一个函数来代替这个功能
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void Select_sort(int* arr,int size)
{
int begin = 0, end = size - 1;//保存序列开始与结尾的下标
while (begin < end)
{
int min = begin;//保存最小值的下标
int max = begin;//保存最大值的下标
for (int i = begin; i <= end; i++)
{
if (arr[i] < arr[min])
{
min = i;//更改最小值的下标
}
if (arr[i] > arr[max])
{
max = i;//更改最大值的下标
}
}
swap(&arr[begin], &arr[min]);
if (begin == max)//防止最大值在begin的位置被最小值换走
{
max = min;
//若最大值的下标正好是begin,则经过一次交换后,
//begin位置上的值已经变成最小值,min位置上的值变为了最大值
//所以要及时调整最大值的下标
//否则下次交换找最大值位置就会找上begin上的最小值
}
swap(&arr[end], &arr[max]);
begin++;
end--;
}
}
int main()
{
int arr[10];
//输入十个整数
printf("输入十个整数:\n");
for (int i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);
}
//打印排序前的数组
printf("排序前:");
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
//选择排序
Select_sort(arr, 10);
printf("\n");
//打印排序后的数组
printf("排序后:");
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
2.1复杂度:
时间复杂度:
空间复杂度:O(1)
2.2稳定性 :
不稳定
3.运行结果:
五、快速排序
1.原理(思路):
1.1 hoare法:
1.将序列最左端的元素定为key,首元素为begin(从左向右移动),末元素为end(从右向左移动)
2.保存begin下标为left,end下标为right
3.end率先向左走,当遇到比key小的元素就停下,随后begin向右走,遇到比key大的元素就停下
4.begin和end上元素的值交换位置,然后end继续向左走,重复第二步,直到begin与end相遇,然后将key与end上的元素的值交换位置,让key的值来到end的位置上(这时key的左边全是比key小的值,右边全是比key大的值)
5.然后将这个序列以key为分界点分为左、右两个序列,分别重复上述步骤,直到最后每个左右序列只剩一个值或不存在左右序列为止,此时序列已经有序
1.2挖坑法:
1.2.1递归:(与hoare法类似)
1.首元素的值作为key保存起来,并将其下标作为坑,首元素为begin(从左向右移动),末元素为end(从右向左移动)首元素为begin(从左向右移动),末元素为end(从右向左移动)
2.保存begin下标为left,end下标为right
3.end率先向左走,当遇到比key小的元素就停下,将end上的值放到坑hole的位置上,然后将end作为新的坑hole,随后begin向右走,遇到比key大的元素就停下,将begin上的值放到hole的位置上,然后将begin作为新的坑hole
4.重复以上步骤,当end和begin相遇,将key的值放到坑hole上
5.然后将这个序列以key为分界点分为左、右两个序列,分别重复上述步骤,直到最后每个左右序列只剩一个值或不存在左右序列为止,此时序列已经有序
1.2.2非递归:
用栈来模拟递归,思路与递归相似
2.代码实现:
2.1 hoare法:
void swap(int* a,int* b)//排序中频繁使用交换,所以写一个函数来代替这个功能
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void Quick_sort(int* arr,int begin,int end)
{
if (begin >= end)//只有一个元素或区域不存在
{
return;
}
int left = begin;
int right = end;
int key = begin;
while (begin < end)
{
while (arr[end] >= arr[key] && begin < end)//右选小
{
end--;
}
while (arr[begin] <= arr[key] && begin < end)//左选大
{
begin++;
}
swap(&arr[begin], &arr[end]);
}
swap(&arr[key], &arr[end]);
key = end;
Quick_sort(arr, left, key - 1);
Quick_sort(arr, key + 1, right);
}
int main()
{
int arr[10];
//输入十个整数
printf("输入十个整数:\n");
for (int i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);
}
//打印排序前的数组
printf("排序前:");
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
//hoare法快速排序
Quick_sort(arr, 0,9);
printf("\n");
//打印排序后的数组
printf("排序后:");
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
2.2挖坑法:
2.2.1递归:
void Quick_sort(int* arr,int begin,int end)
{
if (begin >= end)//只有一个元素或区域不存在
{
return;
}
int left = begin;
int right = end;
int key = arr[begin];
while (begin < end)
{
while (arr[end] >= key && begin < end)//右选小
{
end--;
}
arr[begin] = arr[end];
while (arr[begin] <= key && begin < end)//左选大
{
begin++;
}
arr[end] = arr[begin];
}
arr[end] = key;
int keyi = end;
Quick_sort(arr, left, keyi - 1);
Quick_sort(arr, keyi + 1, right);
}
int main()
{
int arr[10];
//输入十个整数
printf("输入十个整数:\n");
for (int i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);
}
//打印排序前的数组
printf("排序前:");
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
//排序
Quick_sort(arr, 0,9);
printf("\n");
//打印排序后的数组
printf("排序后:");
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
2.2.2非递归:
int sigle_sort(int* arr,int begin,int end)
{
int key = arr[begin];
while (begin < end)
{
while (arr[end] >= key && begin < end)//右选小
{
end--;
}
arr[begin] = arr[end];
while (arr[begin] <= key && begin < end)//左选大
{
begin++;
}
arr[end] = arr[begin];
}
arr[end] = key;
int meeting = end;
return meeting;
}
void Quick_sortNor(int* arr, int begin, int end)
{
stack st;
//先入最右
st.push(end);
//后入最左
st.push(begin);
while (!st.empty())
{
//设定左区间
int left = st.top();
st.pop();
//设定右区间
int right = st.top();
st.pop();
//取中间数并进行一次挖坑法快排
int mid = PartSort(arr, left, right);
//当左区间>=mid-1则证明左区间已经排好序了
if (left < mid - 1)
{
st.push(mid - 1);
st.push(left);
}
//当mid+1>=右区间则证明右区间已经排好序
if (right > mid + 1)
{
st.push(right);
st.push(mid + 1);
}
}
}