本文包括六种常用算法冒泡排序、选择排序、插入排序、归并排序、快速排序、桶排序,具体代码实现如下
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
void bubble_sort(int arr[],int len);
void swap(int *x,int *y);
void select_sort(int arr[],int len);
void insert_sort(int arr[],int len);
void merge(int *array,int start,int mid,int end);
void merge_sort(int arr[], int len);
void merge_sort_recursive(int arr[], int reg[], int start, int end);
void quick_sort(int arr[],int len);
void quick_sort_recursive(int arr[],int start,int end);
void bucket_sort(int arr[],int len);
typedef struct node
{
int num;
struct node *next;
}KeyNode;
void main(){
int arr[] = {22,34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70 };
int len = sizeof(arr)/sizeof(*arr); // len = 14
//insert_sort(arr,len);
//quick_sort( arr,len);
//bucket_sort(arr,len);
bucket_sort(arr,len);
//for (int i = 0; i < len; i++)printf("%d, ",arr[i]);
}
// 冒泡排序,从底下选择有顺序的往上面冒
void bubble_sort(int arr[],int len){
for (int i = 0; i < len-1; i++)
{
for (int j = 0; j < len-i-1; j++)if(arr[j]>arr[j+1])swap(arr+j,arr+j+1);
}
}
// 选择排序,从第一个节点开始,往后选择最小的一个数组和当前的节点互换位置
void select_sort(int arr[],int len){
for (int i = 0; i < len; i++)
{
int k= i;
for (int j = i+1; j < len; j++)
{
if(arr[k]<arr[j]) k=j;
}
swap(arr+i,arr+k);
}
}
// 插入排序,将后面无序的插入到前面有序的数组中
void insert_sort(int arr[],int len){
for (int i = 0; i < len; i++){
int temp = arr[i],k = i-1;
while (k>=0 && temp>arr[k])
{
arr[k+1] = arr[k];
k--;
}
arr[k+1] = temp;
}
}
void swap(int *x,int *y){
int temp;
temp = *x;
*x = *y;
*y = temp;
}
// 归并算法,将数组递归的分成两部分,再对两部分进行顺序合并
void merge_sort_recursive(int arr[], int reg[], int start, int end) {
if(start>=end) return;
int mid = ((end - start)>>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 (int i = start; i <=end; i++)arr[i] = reg[i];
}
void merge_sort(int arr[],int len) {
int reg[len];
merge_sort_recursive(arr, reg, 0, len - 1);
}
// 快速排序,从数组中选择一个基点,递归将数组中大于和小于的值放在其两边
void quick_sort_recursive(int arr[],int start,int end){
if(start>=end)return;
int mid = end;
int left = start,right = end-1;
while (left<right)
{
while (arr[left]<arr[mid] && left<right) left++;
while (arr[right]>arr[mid] && left<right) right--;
swap(arr+right,arr+left);
}
// 处理left=right时该点大于mid的场景
while (arr[left]>arr[mid])swap(arr+left,arr+mid);
quick_sort_recursive(arr,start,left);
quick_sort_recursive(arr,left+1,end);
}
// 快排入口
void quick_sort(int arr[],int len){
quick_sort_recursive(arr,0,len-1);
}
// 桶排序,桶的数量=(max-min)/len+1
void bucket_sort(int arr[],int len){
// 1、获取桶的数量
int max=arr[len-1],min=arr[0],t=0;
for (int i = 0; i < len; i++)
{
if(arr[i]<min) min = arr[i];
if(arr[i]>max) max= arr[i];
}
int bucket = (max-min)/len +1; // 桶的数量
printf("max=%d,min=%d,桶的数量:%d,数组长度:%d\n",max,min,bucket,len);
int temp[len];
for(int i=0;i<bucket;i++){
int bucket[len],k=0;
printf("第%d个桶的数据有:",i);
for (int j = 0; j < len; j++)
{
// 放入桶中
if(i == (arr[j]-min)/len){
bucket[k++] = arr[j];
//printf("%d-",arr[j]);
}
}
// 调用排序
bubble_sort(bucket,k);
// 排序后的桶
for(int i=0;i<k;i++)printf("%d, ",bucket[i]);
// 排序完放入
for (int j = 0; j < k; j++)
{
temp[t++] = bucket[j];
}
}
printf("开始打印数据================\n");
for (int i = 0; i < len; i++)
{
printf("%d, ",temp[i]);
}
}
关于排序的思考
最优雅的永远是在合适的场景选择最合适的工具,算法亦是如此。前三种算法是采用不同的手段进行,由后往前排(冒泡),由前往后排(选择、插入)。而后三种排序个人感觉都采用的分治的思想,将大的化小再通过其固有的方式或者借助其他排序方法排序。