八大排序算法(c语言实现)
小知识:
1)八大排序算法皆是内部排序。
2)稳定的算法在排序的过程中不会改变元素彼此的位置的相对次序。反之不稳定的算法会经常改变这个相对次序。
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最好) | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
冒泡排序 | O(n^2) | O(n^2) | O(n) | O(1) | 稳定 |
选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
简单插入排序 | O(n^2) | O(n^2) | O(n) | O(1) | 稳定 |
希尔排序 | O(n^1.5) | O(n^2) | O(n) | O(1) | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
快速排序 | O(nlogn) | O(n^2) | O(nlogn) | O(nlogn) | 不稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
基数排序 | O(n*k) | O(n*k) | O(n*k) | O(n+k) | 稳定 |
1、冒泡排序
思路:外层从1到n-1,控制排序趟数;内循环依次比较相邻元素,出现逆序就交换。每趟排序把最大的/最小的移到最后面。
#include <stdio.h>
/*
* 功能:冒泡排序,将最大元素放在最后。
* 传入参数:arr,待排序数组;arr_size,待排序数组的元素个数。
*/
void bubble_sort(int* arr, int arr_size)
{
int i,j,tmp;
for (i = 0; i < arr_size-1; ++i) //外层循环控制排序趟数
{
for (j = 0; j < arr_size-1-i; ++j)
{
if (arr[j] > arr[j + 1]) {
tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
/*
* 功能:依次打印数组每个元素。
* 传入参数:arr,待打印元素的数组;arr_size,待打印元素数组的元素格式。
*/
void print_arr(int* arr, int arr_size)
{
int i;
for (i = 0; i < arr_size; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[10] = {2,5,6,4,3,7,9,8,1,0};
print_arr(arr, 10);
bubble_sort(arr, 10);
print_arr(arr, 10);
return 0;
}
2、选择排序
思路:首先在未排序元素中,找到最大/最小值,存放在排序序列的起始位置;然后再在剩余未排序元素中寻找最大/最小值,放到已排序序列的末尾。
#include <stdio.h>
/*
* 功能:选择排序,将最大元素放到最后。
* 传入参数:arr, 待排序数组;arr_size,待排序数组的元素个数。
*/
void select_sort(int* arr, int arr_size)
{
int i, j, tmp, min_index;
for (i = 0; i < arr_size-1; ++i)
{
min_index = i;
for (j = i+1; j < arr_size; ++j)
{
if (arr[j] < arr[min_index]) {
min_index = j;
}
}
if (min_index != i) {
tmp = arr[i];
arr[i] = arr[min_index];
arr[min_index] = tmp;
}
}
}
/*
* 功能:依次打印数组每个元素。
* 传入参数:arr,待打印元素的数组;arr_size,待打印元素数组的元素格式。
*/
void print_arr(int* arr, int arr_size)
{
int i;
for (i = 0; i < arr_size; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[10] = { 2,5,6,4,3,7,9,8,1,0 };
print_arr(arr, 10);
select_sort(arr, 10);
print_arr(arr, 10);
return 0;
}
3、简单插入排序
思路:构建有序序列,对于未排序的数据,从已排序序列中从后往前扫描,找到相应位置并插入。像扑克牌的理牌。
#include <stdio.h>
/*
* 功能:简单插入排序。将最大元素放到最后。
* 传入参数:arr, 待排序数组;arr_size,待排序数组的元素个数。
*/
void insert_sort(int* arr, int arr_size)
{
int i, j, key;
//从第二个数字开始,每一个数字都试图跟它前一个比较并交换,直到前一个数字不存在或者比它小或相等时停下来。
for (i = 1; i < arr_size; ++i)
{
key = arr[i];
j = i - 1;
while (j >= 0 && arr[j] > key)
{
arr[j + 1] = arr[j];
--j;
}
arr[j + 1] = key;
}
}
/*
* 功能:依次打印数组每个元素。
* 传入参数:arr,待打印元素的数组;arr_size,待打印元素数组的元素格式。
*/
void print_arr(int* arr, int arr_size)
{
int i;
for (i = 0; i < arr_size; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[10] = { 2,5,6,4,3,7,9,8,1,0 };
print_arr(arr, 10);
insert_sort(arr, 10);
print_arr(arr, 10);
return 0;
}
4、希尔排序
思路:希尔排序也是一种插入排序,它是简单插入排序经改进后一个更高效的版本,也称为缩小增量排序。
#include <stdio.h>
/*
* 功能:希尔排序。将最大元素放到最后。
* 传入参数:arr,待排序数组;arr_size,待排序数组的元素个数。
*/
void shell_sort(int* arr, int arr_size)
{
int gap,i, j, tmp;
for (gap = arr_size / 2; gap > 0; gap /= 2)
{
for (i = gap; i < arr_size; ++i)
{
j = i;
while (j - gap >= 0 && arr[j-gap] > arr[j]) //插入排序采用交换法
{
tmp = arr[j];
arr[j] = arr[j - gap];
arr[j - gap] = tmp;
j -= gap;
}
}
}
}
/*
* 功能:依次打印数组每个元素。
* 传入参数:arr,待打印元素的数组;arr_size,待打印元素数组的元素格式。
*/
void print_arr(int* arr, int arr_size)
{
int i;
for (i = 0; i < arr_size; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[10] = { 2,5,6,4,3,7,9,8,1,0 };
print_arr(arr, 10);
shell_sort(arr, 10);
print_arr(arr, 10);
return 0;
}
5、归并排序
思路:将已有序的子序列合并,得到完全有序的序列。
先使每个子序列有序,再使子序列段间序列有序。若将两个有序表合成一个有序表,称为2-路归并。
它使用了递归分治的思想:相当于,左半边用尽,则取右边元素;右半边用尽,则取左边元素;右半边的当前元素小于左半边的当前元素,则取右半边元素;右半边的当前元素大于左半边的当前元素,则取左半边的当前元素。
#include <stdio.h>
#include <stdlib.h>
/*
* 功能:归并两个有序区。
* 传入参数:nums,待排序数组;low,归并区的最小下标;mid,归并区的中间下标;high,归并区的最大下标。
*/
void merge(int* nums, int low, int mid, int high)
{
int* tmp = (int*)malloc((high - low + 1) * sizeof(int));
if (NULL == tmp) {
return;
}
int i = low;
int j = mid + 1;
int k = 0;
while (i <= mid && j <= high)
{
if (nums[i] <= nums[j]) {
tmp[k++] = nums[i++];
}
else {
tmp[k++] = nums[j++];
}
}
while (i <= mid)
{
tmp[k++] = nums[i++];
}
while (j <= high)
{
tmp[k++] = nums[j++];
}
for (i = 0; i < k; ++i)
{
nums[low + i] = tmp[i];
}
}
/*
* 功能:归并排序。将最大元素放到最后。
* 传入参数:nums,待排序数组;low,待排序数组最小下标;high,待排序数组最大下标。
*/
void merge_sort(int* nums, int low, int high)
{
if (low < high) {
int mid = (low + high) / 2;
merge_sort(nums, low, mid);
merge_sort(nums, mid + 1, high);
merge(nums, low, mid, high);
}
}
/*
* 功能:依次打印数组每个元素。
* 传入参数:arr,待打印元素的数组;arr_size,待打印元素数组的元素格式。
*/
void print_arr(int* arr, int arr_size)
{
int i;
for (i = 0; i < arr_size; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[10] = { 2,5,6,4,3,7,9,8,1,0 };
print_arr(arr, 10);
merge_sort(arr, 0, 9);
print_arr(arr, 10);
return 0;
}
6、快速排序
思路:挖坑填数+分治法
1)从序列中选择一个基准数;
2)将序列中的所有数依次遍历,比它大的数位于其右侧,比它小的数位于其左侧。
3)重复前两步,对左右序列分别排序,直到序列有序(子序列只剩下一个数)。
#include <stdio.h>
/*
* 功能:按照基准值,将传入序列分为小于基准值的序列和大于基准值的序列,在中间位置插入该基准值。基准值选择为序列的第一个值。
* 传入参数:nums,待排序数组;low,待排序数组的最小下标;high,待排序数组的最大下标。
* 返回值:基准值的位置。
*/
int partition(int *nums, int low, int high)
{
int elem = nums[low];
while (low < high)
{
while (low<high && nums[high]>elem)
{
--high;
}
nums[low] = nums[high];
while (low < high && nums[low] < elem)
{
++low;
}
nums[high] = nums[low];
nums[low] = elem;
}
return low;
}
/*
* 功能:快速排序。将最大元素放在最后。
* 传入参数:nums,待排序数组;low,待排序数组的最小小标;high,待排序数组的最大下标。
* 传出参数:nums,排序后的数组。
*/
void quick_sort(int* nums, int low, int high)
{
if (low < high) {
int pos = partition(nums, low, high);
quick_sort(nums, low, pos);
quick_sort(nums, pos + 1, high);
}
}
/*
* 功能:依次打印数组每个元素。
* 传入参数:arr,待打印元素的数组;arr_size,待打印元素数组的元素格式。
*/
void print_arr(int* arr, int arr_size)
{
int i;
for (i = 0; i < arr_size; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[10] = { 2,5,6,4,3,7,9,8,1,0 };
print_arr(arr, 10);
quick_sort(arr, 0, 9);
print_arr(arr, 10);
return 0;
}
7、堆排序
1)二叉堆的定义:完全二叉树或近似完全二叉树。二叉堆满足两个特性:
a.父节点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
b.每个节点的左子树和右子树都是二叉堆。
当父节点的键值总是大于或等于任何一个子节点的键值时,是大根堆;当父节点的键值总是小于或等于任何一个子节点的键值时,是小根堆。
2)二叉堆一般使用数组存储。
3)思路:
a.将无序序列建成一个小顶堆,输出堆顶元素;
b.将堆顶元素与末尾元素交换;
c.重新调整结构,使其满足堆定义。重复bc步骤,直到输出全部元素。
#include <stdio.h>
#include <stdlib.h>
/*
* 功能:从上到下调整堆结构
*/
void adjust_down(int* nums, int k, int len)
{
nums[0] = nums[k];
int i;
for (i = k * 2; i <= len; i *= 2)
{
if (i < len && nums[i + 1] < nums[i]) {
++i;
}
if (nums[0] <= nums[i]) {
break;
}
else {
nums[k] = nums[i];
k = i;
}
}
nums[k] = nums[0];
}
/*
* 功能:构建最小堆。
*/
void build_min_heap(int *nums, int len)
{
int i;
for (i = len / 2; i > 0; --i)
{
adjust_down(nums, i, len);
}
}
/*
* 功能:堆排序,并从小到大依次输出排序后的元素。
*/
void heap_sort(int* nums, int len, int *tmp)
{
int i, j;
for (i = 0; i < len; ++i)
{
tmp[i + 1] = nums[i];
}
build_min_heap(tmp, len);
for (i = len; i >= 1; --i)
{
printf("%d ", tmp[1]);
j = tmp[1];
tmp[1] = tmp[i];
tmp[i] = j;
adjust_down(tmp, 1, i - 1);
}
}
/*
* 功能:依次打印数组每个元素。
* 传入参数:arr,待打印元素的数组;arr_size,待打印元素数组的元素格式。
*/
void print_arr(int* arr, int arr_size)
{
int i;
for (i = 0; i < arr_size; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[10] = { 2,5,6,4,3,7,9,8,1,0 };
int after_sort[11] = { 0 };
print_arr(arr, 10);
heap_sort(arr, 10, after_sort);
return 0;
}
8、基数排序
思路:
a.取得数组中的最大值;
b.根据最大值的位数,从低到高对数组进行计数排序;
#include <stdio.h>
#include <stdlib.h>
int get_max(int* nums, int len)
{
int i;
int max = nums[0];
for (i = 1; i < len; ++i)
{
if (nums[i] > max) {
max = nums[i];
}
}
return max;
}
void count_sort(int* nums, int len, int exp)
{
int* tmp = (int*)malloc(len * sizeof(int));
if (NULL == tmp) {
return;
}
int queue[10] = { 0 };
int i;
for (i = 0; i < len; ++i)
{
++queue[(nums[i] / exp)%10];
}
for (i = 1; i < 10; ++i)
{
queue[i] += queue[i - 1];
}
for (i = len - 1; i >= 0; --i)
{
tmp[queue[(nums[i] / exp) % 10] - 1] = nums[i];
--queue[(nums[i] / exp) % 10];
}
for (i = 0; i < len; ++i)
{
nums[i] = tmp[i];
}
}
void radix_sort(int* nums, int len)
{
int exp;
int max = get_max(nums, len);
for (exp = 1; max / exp > 0; exp *= 10)
{
count_sort(nums, len, exp);
}
}
/*
* 功能:依次打印数组每个元素。
* 传入参数:arr,待打印元素的数组;arr_size,待打印元素数组的元素格式。
*/
void print_arr(int* arr, int arr_size)
{
int i;
for (i = 0; i < arr_size; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[10] = { 2,5,6,4,3,7,9,8,1,0 };
print_arr(arr, 10);
radix_sort(arr, 10);
print_arr(arr, 10);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构