排序
简单选择排序
每次从未排序的元素中选择最大(小)的放入排序序列 O(n^2)
C语言
#include <stdio.h>
#include <stdlib.h>
void swap(int *p1,int *p2){
int t;
t = *p1;
*p1 = *p2;
*p2 = t;
}
void printArray(const int *array,int size){
for(int i=0;i<size;i++){
printf("%d ",array[i]);
}
putchar('\n');
}
void selectionSort(int *array,int size){
int minv,min;
for(int i=0;i<size-1;i++){
minv = array[i];
min = i;
for(int j=i+1;j<size;j++){
if(array[j]<minv){
minv = array[j];
min = j;
}
}
if(min - i) swap(&array[i],&array[min]);
printf("%d: ",i);
printArray(array,size);
}
}
int main(){
int array[6]={
19,54,4,30,70,2};
selectionSort(array,6);
return 0;
}
简单插入排序
每次把未排序的元素中的第一个元素插入到一已排序的序列中。最坏和平均都是O(n^2)
C语言
#include <stdio.h>
#include <stdlib.h>
void swap(int *p1,int *p2){
int t;
t = *p1;
*p1 = *p2;
*p2 = t;
}
void printArray(const int *array,int size){
for(int i=0;i<size;i++){
printf("%d ",array[i]);
}
putchar('\n');
}
void insertionSort(int *array,int size){
// 把一个固定,把当前元素依次和前面的比较
//
int x;
for(int i=1,j;i<size;i++){
x=array[i]; // 把
for(j=i; j>0 && array[j-1]>x;j--){
array[j]=array[j-1];
}
array[j]=x;
printf("%d: ",i);
printArray(array,size);
}
}
int main(){
int array[6]={
19,54,4,30,70,2};
insertionSort(array,6);
return 0;
}
冒泡排序
从开始到序列结束两两进行比较,逆序则交换,到序列结束,谓之一趟排序。复杂度 O(n^2) 稳定
C语言
#include <stdio.h>
#include <stdlib.h>
void swap(int *p1,int *p2){
int t;
t = *p1;
*p1 = *p2;
*p2 = t;
}
void printArray(const int *array,int size){
for(int i=0;i<size;i++){
printf("%d ",array[i]);
}
putchar('\n');
}
void bubbleSort(int *array,int size){
int flag=1; // 是否进行交换。
for(int i=0;flag && i<size;i++){
for(int j=0;j<size-1-i;j++){
if(array[j]> array[j+1]){
swap(&array[j],&array[j+1]);
flag=1;
}
}
printf("%d",i);
printArray(array,size);
}
}
int main(){
int array[6]={
19,54,4,30,70,2};
bubbleSort(array,6);
return 0;
}
希尔排序(Shell Sort)
变步长的插入排序,效率与步长序列选取有关,争取选用奇数步长,比如 5-sort,3-sort,1-sort
堆排序
优先队列(堆)删除堆顶:O(log N)
按序出队
连续删除N次堆顶 => 排序
时间负杂度: O(N log N)
额外空间负杂度: O(N)
C语言
#include <stdio.h>
#include <stdlib.h>
void swap(int *p1,int *p2){
int t;
t = *p1;
*p1 = *p2;
*p2 = t;
}
void printArray(const int *array,int size){
for(int i=0;i<size;i++){
printf("%d ",array[i]);
}
putchar('\n');
}
// 向下过滤
void percolateDown(int k,int *array,int size){
int x;
x=array[k];
int i,child;
for(i=k;i*2+1 <size;i=child){
child = i*2+1;
// 大顶堆
if(child!=size-1 && array[child+1] >array[child]){
child++;
}
if(x < array[child]){
array[i] = array[child];
}else{
break;}
}
array[i]=x;
}
void heapSort(int *array,int size){
// 完全二叉树,删堆顶就是把元素给交换一下。
// 创建堆 size/2-1时父亲结点,从最后一个有儿子的结点向下过滤
for(int i=size/2-1;i>=0;i--){
percolateDown(i,array,size);
}
for(int i=size-1;i>0;i--){
swap(&array[0],&array[i]);
percolateDown(0,array,i);
}
}
int main(){
int array[6]={
19,54,4,30,70,2};
heapSort(array,6);
return 0;
}
分治法
分治法:分而治之,
可行性:
-
大规模的问题能分解成若干小规模问题
-
小规模问题求解后,不难合并求大规模问题的解。
-
小规模问题求解可能比大规模问题简单
有意义:
-
大规模问题求解负杂度> O(N)
N/2+N/2 = N (N/2)^2 +(N/2)^2 < N^2
归并排序
(分治法)
C语言
#include <stdio.h>
#include <stdlib.h>
void swap(int *p1,int *p2){
int t;
t = *p1;
*p1 = *p2;
*p2 = t;
}
void printArray(const int *array,int size){
for(int i=0;i<size;i++){
printf("%d ",array[i]);
}
putchar('\n');
}
void msort(int *array,int *tmp,int left,int right){
if(left>=right) return;
int mid;
mid = (left+right)/2;
msort(array,tmp,left,mid);
msort(array,tmp,mid+1,right);
merge(array,tmp,left,mid+1,right);
}
void merge(int *a,int *t,int li,int ri,int re){
int le,ti,begin;
le = ri-1;
begin=ti = li;
while(li<=le && ri<=re){
if(a[li]<=a[ri]) t[ti++] = a[li++];
else t[ti++] = a[ri++]
}
while(li<=le) t[ti++] = a[li++];
while(ri<=re) t[ti++] = a[ri++];
for(int i=begin;i<=re;i++) a[i]=t[i];
}
void mergeSort(int *array,int size){
int *tmp;
tmp = (int*)malloc(sizeof(int) * size);
if(!tmp) return;
msort(array,tmp,0,size-1);
free(tmp);
}
int main(){
int array[6]={
19,54,4,30,70,2};
mergeSort(array,6);
return 0;
}
快速排序
分类思想。分割的点要选择好, (分治法)
一般取中位数,不一定很好但一定不最差。
C语言
#include <stdio.h>
#include <stdlib.h>
void swap(int *p1,int *p2){
int t;
t = *p1;
*p1 = *p2;
*p2 = t;
}
void printArray(const int *array,int size){
for(int i=0;i<size;i++){
printf("%d ",array[i]);
}
putchar('\n');
}
int medianPivot(int *a,int left,int right){
int mid = (left+right)/2;
if(a[left]>a[mid]) swap(&a[left],&a[mid]);
if(a[left]>a[right]) swap(&a[left],&a[right]);
if(a[mid]>a[right]) swap(&a[mid],&a[right]);
swap(&a[mid],&a[right-1]);
return a[right-1];
}
// 低于20个插入排序,高于20个快排
const int cutoff=20;
void insertionSort(int *array,int size){
// 把一个固定,把当前元素依次和前面的比较
//
int x;
for(int i=1,j;i<size;i++){
x=array[i]; // 把
for(j=i; j>0 && array[j-1]>x;j--){
array[j]=array[j-1];
}
array[j]=x;
printf("%d: ",i);
printArray(array,size);
}
}
void qSort(int *array,int left,int right){
int pivort;
if(right-left <cutoff){
insertionSort(a+left,right-left+1);
}else{
// 选择一个中位数
pivot=medianPivot(a,left,right);
int i,j;
i=left+1;
j=right-2;
while(1){
while(a[i]<pivot) i++; // i从左
while(a[j]<pivot) j--; // j从右
if(i<j) swap(&a[i],&a[j]);
else break;
}
swap(&a[i],&a[right-1]);
qSort(a,left,i-1);
qSort(a,i+1,right);
}
}
void quickSort(int *array,int size){
// 内部递归
qSort(array,0,size-1);
}
int main(){
int array[6]={
19,54,4,30,70,2};
quickSort(array,6);
return 0;
}
桶排序
输入是由一个随机过程产生的[0, 1)区间上均匀分布的实数。将区间[0, 1)划分为n个大小相等的子区间(桶),每桶大小1/n:[0, 1/n), [1/n, 2/n), [2/n, 3/n),…,[k/n, (k+1)/n ),…将n个输入元素分配到这些桶中,对桶中元素进行排序,然后依次连接桶输入0 ≤A[1…n] <1辅助数组B[0…n-1]是一指针数组,指向桶(链表)