数据结构与算法实践系列文章(九)排序

排序

简单选择排序

每次从未排序的元素中选择最大(小)的放入排序序列 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]是一指针数组,指向桶(链表

基数排序

猜你喜欢

转载自blog.csdn.net/qq_37256896/article/details/117074191