排序方式
- 冒泡排序
- 直接插入排序
- 折半插入排序
- 希尔排序
- 选择排序
- 鸡尾酒排序
- 堆排序
- 快速排序
- 归并排序
- 计数排序
1.冒泡排序
算法思路:冒泡排序就是把小的元素往前调或者把大的元素往后调,比较是相邻的两个元素比较,交换也发生在这两个元素之间。
时间复杂度:冒泡排序的最好时间复杂度是O(n),最差时间复杂度是O(n^2)。
代码:
void bubble_sort(int arr[],size_t n){
size_t i,j;
for(i=0;i<n;i++){
bool hasSwap = false;
for(j=1;j<n-i;j++){
if(arr[j-1]>arr[j]){
swap(&arr[j-1],&arr[j]);
hasSwap = true;
}
}
if(!hasSwap){
break;
}
}
}
2.直接插入排序
算法思路:把一个数插入到一个有序的数列中,把数组中的元素逐个插入到一个有序的数列当中,从数组中的第一个元素开始,
把这个元素记录为key,把key插入到前面有序的数组中。
时间复杂度:O(n^2)
代码:
void insert_sort(int arr[],size_t n){
int i,j;
for(i=1;i<n;i++){
int key = arr[i];
for(j=i-1;j>=0&&arr[j]>key;--j){
arr[j+1] = arr[j];
}
arr[j+1] = key;
}
}
3.折半插入排序
算法思路:本质上与直接插入无异,但通过折半查找的方式找到插入位置,提高效率。
时间复杂度:O(n^2)
代码:
void bin_insert_sort(int arr[],size_t n){
int i,j;
for(i=1;i<n;i++){
int key = arr[i];
int left = 0;
int right = i-1;
while(left <= right){
int mid = (left+right)/2;
if(key<arr[mid]){
right = mid-1;
}else{
left = mid+1;
}
}
for(j=i-1;j>=left;j--){
arr[j+1] = arr[j];
}
arr[j+1] = key;
}
}
4.希尔排序
算法思路:本质也是插入,分组,组内进行插入排序,避免像直接插入时大量地移动一个数据,把一个数据放到大致的位置。
时间复杂度:O(n^1.3)
代码:
void shell_sort(int arr[],size_t n){
size_t step;
int i,j;
for(step=n/2;step>0;step=step/2){
for(i=step;i<n;i++){
int key = arr[i];
for(j=i-step;j>=0&&arr[j]>key;j=j-step){
arr[j+step] = arr[j];
}
arr[j+step] = key;
}
}
}
5.选择排序
算法思路:每次循环找到一个最大值,将最大值与最后一个值进行交换,交换后确定最后一个是最大的,数组长度减小1.
时间复杂度:O(n^2)
代码:
void choice_sort(int arr[],size_t n){
size_t i,j;
for(i=0;i<n-1;i++){
int m = 0;
for(j=1;j<n-i;j++){
if(arr[j]>arr[m]){
m = j;
}
}
if(m != n-1-i){
swap(&arr[m],&arr[n-1-i]);
}
}
}
6.鸡尾酒排序
算法思路:每次遍历找到一个最大值和一个最小值,将最大值放到数组末尾,将最小值放到数组开始位置。
时间复杂度:O(n^2)
代码:
void cook_tail_sort(int arr[],size_t n){
size_t i,j;
for(i=0;i<n/2;i++){
int max = i;
int min = i;
for(j=i+1;j<n-i;j++){
if(arr[max]<arr[j]){
max = j;
}
if(arr[min]>arr[j]){
min = j;
}
}
if(max != n-1-i)
swap(&arr[max],&arr[n-1-i]);
if(min == n-1-i)
min = max;
if(min != i)
swap(&arr[min],&arr[i]);
}
}
7.堆排序
算法思路:把数组调整成大堆,把第一个元素和最后一个元素进行交换,不考虑最后一个元素,重新调整成大堆重复上面的步骤。
时间复杂度:O(nlgn)
代码:
void reheap(int arr[],size_t index,size_t n){
size_t child = 2*index+1;
int key = arr[index];
while(child < n){
if(child+1<n && arr[child]<arr[child+1]){
++child;
}
if(key < arr[child]){
arr[index] = arr[child];
}else{
break;
}
index = child;
child = 2*index+1;
}
arr[index] = key;
}
void heap_sort(int arr[],size_t n){
int i;
for(i=n/2;i>=0;i--){
reheap(arr,i,n);
}
for(i=n-1;i>0;i--){
swap(&arr[0],&arr[i]);
reheap(arr,0,i);
}
}
8.快速排序
算法思路:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,
然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
时间复杂度:O(nlog2n)
代码:
t arr[],int left,int right){
if(left >= right)
return;
int i=left;
int j=right;
int key = arr[i];
while(i<j){
while(i<j&&arr[j]>=key){
--j;
}
arr[i] = arr[j];
while(i<j&&arr[i]<=key){
++i;
}
arr[j] = arr[i];
}
arr[i] = key;
if(i-1-left+1>1)
quick(arr,left,i-1);
if(right-(i+1)+1>1)
quick(arr,i+1,right);
}
9.归并排序
算法思路:归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并排序是一种稳定的排序方法。
时间复杂度:O(nlog2n)
代码:
void mergeArr(int arr[],size_t n){
if(n<=1)
return;
int mid = n/2;
int len = mid;
int *prr = malloc(sizeof(int)*len);
size_t i;
for(i=0;i<len;i++){
prr[i] = arr[i];
}
size_t j,k;
i=0;
j=mid;
k=0;
while(i<len && j<n){
if(prr[i]<arr[j]){
arr[k++] = prr[i++];
}else{
arr[k++] = arr[j++];
}
}
while(i<len){
arr[k++] = prr[i++];
}
free(prr);
}
void merge(int arr[],int left,int right){
if(left >= right)
return;
int mid = (left+right)/2;
}
void merge_sort(int arr[],size_t n){
if(n<=1){
return;
}
int mid = n/2;
merge_sort(arr,mid);
merge_sort(arr+mid,n-mid);
mergeArr(arr,n);
}
计数排序
算法思路:计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出。
时间复杂度:Ο(n+k)(其中k是整数的范围)
代码:
void count_sort(int arr[],size_t n){
int max = arr[0];
int min = arr[0];
size_t i;
for(i=1;i<n;i++){
if(max < arr[i]){
max = arr[i];
}
if(min > arr[i]){
min = arr[i];
}
}
int cnt = max-min+1;
int *prr = malloc(cnt*sizeof(int));
for(i=0;i<n;i++){
prr[i] = 0;
}
for(i=0;i<n;i++){
prr[arr[i]-min]++;
}
size_t j=0;
for(i=0;i<cnt;i++){
while(prr[i] > 0){
arr[j++] = i+min;
--prr[i];
}
}
}