排序算法

来源:互联网 发布:php class实例化 编辑:程序博客网 时间:2024/06/01 13:27

总结

                    稳定        时间复杂度    平均时间复杂度     空间复杂度

冒泡排序                       O(n2)               O(n2)                    O(1)

选择排序         ×               O(n2)               O(n2)                    O(1)

插入排序         √               O(n2)               O(n2)                    O(1)

二叉排序       √/×             O(n2)             O(n*log2n)              O(n)

快速排序         ×               O(n2)             O(n*log2n)         O(log2n )~O(n)

基数排序                   O(n*logrm)         O(n*logrm)             O(2r)    【注】r为基数,m为堆数

希尔排序         ×                 O                    O                        O(1)

堆排序            ×            O(n*log2n)         O(n*log2n)              O(1) 

归并排序         

锦标赛排序,类似于二叉树排序。

冒牌排序

for (int i = 0; i < size - 1; i++) {         for (int j = 0; j < size - i - 1; j++) {             if (array[j+1] < array[j]) {                 int tmp = array[j+1];     array[j+1] = array[j]; array[j] = tmp;         }     } }

选择排序

//每次选择最小的一个元素,进行位置交换。void select_sort(int array[], int size){    int i, j, tmp;    for (i =0; i < size-1; i++ ) {        index = i;        for (j = i+1; j < size; j++) {            //选择剩余元素中最小的一个元素,记录在index中            if (array[index] > array[j])                index = j;        }        if (i != index) {            //进行元素的交换            tmp = array[index];            array[index] = array[i];            array[i] = tmp;        }    }}

插入排序

//在一个已经有序的小序列基础上,一次插入一个元素。void insert_sort(int array[], int size){    int i, j, tmp;    for (i = 1; i <= size; i++) {        tmp = array[i]; //待插入的元素        j = i-1;        //与已排序的数逐一比较大小,大于tmp时,该数移后        while ((j > 0) && (array[j] > tmp)) {            array[j+1] = array[j];            j--;        }        array[j+1] = tmp;    }}

快速排序

  • 快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。

基本思想

  1. 先从数列中取出一个数作为基准数。
  2. 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
  3. 再对左右区间重复第二步,直到各区间只有一个数。

【注】:进行函数调用时,传入的参数为:quick_sort(data,0, size-1);

void swap(int *array, int x, int y){    int tmp = array[x];    array[x] = array[y];    array[y] = tmp;}int partition1(int *array, int start, int end) {    int pos = (start + end) / 2;    swap(array,pos,end);    int key = array[end];    int i = start-1;    for(int j=start;j<=end;++j){        if(array[j]<key){            swap(array,++i,j);        }       }      swap(array,++i,end);    return i;}int partition(int *array, int start, int end) {    int pos = (start+end)/2;    int low = start+1;    int high = end;    int key = array[pos];    swap(array, pos, start);    while (low < high) {        while (low < high && array[low] <= key)            low++;        while (low < high && array[high] > key)            high--;        if (low >= high)            break;        swap(array, low, high);    }    if (array[low] > key) {        swap(array, start, low-1);        return low-1;    } else {        swap(array, start, low);        return low;    }}void quick_sort(int *array, int start, int end){    if (start >= end) {        return;    }       int pos = partition(array, start, end);    quick_sort(array, start, pos-1);    quick_sort(array, pos+1, end);}


二叉排序

//生成二叉排序树,然后将二叉树采用中序遍历重新对array赋值struct node{    int value;    struct node *left;    struct node *right;};struct node *new_node(int value){    struct node *new_node = (struct node*)malloc(sizeof(struct node));    if (node) {        node->value = value;        node->left = NULL;        node->right = NULL;    }    return node;}void insert_to_tree(struct node *root, struct node *node){    struct node *tmp = root, *prev = tmp;    while (tmp) {        prev = tmp;        if (tmp->value < node->value) {            tmp = tmp->right;        } else {            tmp = tmp->left;        }        }    if (prev->value < node->value) {        prev->right = node;    } else {        prev->left = node;    }}int binary_tree_sort(int array[], int size){    int i = 0;    struct node *root = new_node(array[i]);    struct node *node = NULL;    struct stack *s = NULL;    for (i = 1; i < size; i++) {        node = new_node(array[i]);        if (!node) {            return 0;        }          insert_to_tree(root, node);    }    //中序遍历二叉树,重新填充数组    s = create_stack();    if (s == NULL) {        printf("Create stack failed!\n");        return 0;    }    node = root;    i = 0;    while (node || !is_empty(s)){        while (node) {            push(&s, node);            node = node->left;        }            node = pop(&s);        array[i] = node->value;        node = node->right;        i++;        if (i >= size) {            break;        }    }       destroy_stack(&s);    return (i <= size);}

基数排序   

int find_max_num(int array[], int size){    int i = 0, max = 0;    for (; i < size; i ++) {        if (array[i] > max) {            max = array[i];        }    }     return max;}int get_loop_times(int num){    int loop = 0, tmp = 0;    do {        tmp  = num / 10;        loop++;    } while (tmp != 0);    return loop;}//将数字分配到各自的桶中,然后按照桶的顺序输出排序结果void __radix_sort(int array[], int size, int loop){    //建立一组桶    int buckets[10][size] = {0};    /*        求桶的index的除数        如798             个位桶index = (798 / 1) % 10 = 8;             十位桶index = (798 / 10) % 10 = 9;            百位桶index = (798 / 100) % 10 = 7    */    int tmp_num = (int) pow(10, loop-1);    int i, j, index, k;    for (i = 0; i < size; i++) {        index = (array[i] / tmp_num) % 10;        for (j = 0; j < size; j++) {                if (buckets[index][j] == 0) {                buckets[index][j] = array[i];                break;            }        }    }    //将桶中的数,倒回到原有数组中    k = 0;    for (i = 0; i < 10; i++) {        for (j = 0; i < size; j++) {            if (buckets[i][j] != 0) {                array[k] = buckets[i][j];                buckets[i][j] = 0;                k++;            }        }    }}//从个位开始,向高位依次放入桶中,进行排序void radix_sort(int array[], int size){    //获取数组中的最大数    int max_num = find_max_num(array, size);    //获取最大数的位数,次数也是再分配的次数    int loop_times = get_loop_times(max_num);    int i = 0;    //对每一位进行桶分配    for (i = 1; i <= loop_times; i++) {        __radix_sort(array, size, i);    }}

希尔排序

  • 插入排序的一种,是针对直接插入排序算法的改进。本质上是一种分组插入排序法。

基本思想:

  • 先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插人排序;
  • 然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

代码实现

void shellPass(int *R,int n, int d){//希尔排序中的一趟排序,d为当前增量    int tmp;    for(i=d+1; i<=n;i++) //将R[d+1..n]分别插入各组当前的有序区        if(R[i]<R[i-d]){            tmp=R[i];            j=i-d; //R[0]只是暂存单元,不是哨兵            do {//查找R[i]的插入位置                R[j+d] = R[j]; //后移记录                j=j-d; //查找前一记录             }while(j>0 && tmp < R[j]);             R[j+d]=tmp; //插入R[i]到正确的位置上       }    }} void  shellSort(int *R, int n){    int increment = n; //增量初值,不妨设n>0    do {          increment=increment/3 +1; //求下一增量          shellPass(R,increment); //一趟增量为increment的Shell插入排序    }while(increment>1)}

堆排序

: 

  • n个元素序列{k1,k2,...,ki,...,kn},当且仅当满足下列关系时称之为堆:
    1. 堆中某个节点的值总是不大于或不小于其父节点的值
    2. 堆总是一棵完全树(若树的高度为H,则1~H-1层节点的个数都达到最大值)

  • 堆一般用数组来表示,假设节点的下标为i,则:
    • Parent(i) :  return Floor(i/2);
    • Left(i):       return 2*i + 1;
    • Right(i):   return 2*i + 2;
  • 含有N个元素的堆A的高度为Floor(lgN)

基本思想:

  • 堆是一个完全二叉树,故而其最下层的叶子节点是从左至右存在的
  • 最小堆的建立:
  • 先建立一个最小堆,然后依次进行如下操作:
    • 将堆顶与 index交换,然后重新调整size为0~index-1的堆
    • 重复以上操作,直到堆的大小为0

算法实现:

inline void swap(int *a, int num1, int num2){        int tmp = a[num1];        a[num1] = a[num2];        a[num2] = tmp;}/* 对该数进行下滤操作,直到该数比左右节点都小就停止下滤。   即对某个根节点的值进行位置下降调整,使该值比其左右子节点都小;   若该节点是叶子节点,则无法while循环 */void PercolateDown(int num[] , int index,int size) {    int min;//最小指向下标    while (index * 2 + 1<size) {        //若该节点有左子结点,则假设该节点为最小        min = index * 2 + 1;        if (index * 2 + 2<size) {//若有右子节点,比较获得左右子节点的最小值            if (num[min] > num[index * 2 + 2]) {                min = index * 2 + 2;            }        }        if (num[index] < num[min]) {//当前的节点小于左右子节点,则循环结束            break;        } else {            Swap(num, index, min);//将当前节点与最小子节点进行交换            index = min;// 重设下标,继续对该节点进行下虑        }    }// while  }/* 建堆方法,只需线性时间建好;   建堆的结果:数组的第一个元素(即树根)是所有元素中的最小值,索引小于等于size/2-1的其它元素(即其它非叶子节点)的值都是其所在子树的最小值 */void BuildHeap(int num[] ,int size) {    int i;     //从最后一个非叶子节点开始,对每个非叶子节点进行最小根调整,保证每个根节点都是其子树中的最小值    for (i = size / 2 - 1; i >= 0; i--) {           PercolateDown(num, i,size);    }}void HeapSort(int num[] ,int size){    int i;    int iLength=size;        //建立小顶堆    BuildHeap(num,size);    /*        堆排序-建立大顶堆,数组按由大到小排序        基本思路:            从数组的最后一个元素开始,将其与第一个元素交换,然后对该元素进行下虑操作        此时第一个元素总是当前堆的最小值。    */    for (i = iLength - 1; i >= 1; i--) {           Swap(num, 0, i);         size--; //每交换一次,将堆的规模减小一次        PercolateDown(num, 0, size);//将新的首元素下虑操作    }   }

归并排序

工作原理

  1. 将序列每相邻两个数字进行归并操作,形成个序列,排序后每个序列包含两个元素
  2. 将上述序列再次归并,形成个序列,每个序列包含四个元素
  3. 重复步骤2,直到所有元素排序完毕

代码实现

递归实现

void merge_sort(int array[], unsigned int first, unsigned int last){        int mid = 0;        if(first<last)        {                /*mid = (first+last)/2;*/ /*注意防止溢出*/                /*mid = first/2 + last/2;*/                /*mid = ((first & last) + (first ^ last) >> 1);*/                mid = ((first & last) + ((first ^ last) >> 1));    /*修正上一句优先级错误*/                merge_sort(array, first, mid);                merge_sort(array, mid+1,last);                merge(array,first,mid,last);        }}

原地merge

void merge(int array[], int low,int mid,int high){    int  j = mid+1, k = 0;    while(j <= high) {        if(array[j-1] < array[j])            break;        tmp = array[j];        k = j-1;        while ( k >= 0 && tmp < array[k]){            array[k + 1] = array[k];            k--;        }        array[k] = tmp;        j++;    }}

增加一个临时数组来merge

void merge(int array[], int low,int mid,int high){    int tmp_arr[high-low+1] = {0};    int i = low, j = mid+1, k = 0;    while(i <= mid && j <= high){        if(array[i] < array[j]) {            tmp_arr[k++] = array[i++];            } else {            tmp_arr[k++] = array[j++];        }    }    while(i <= mid)        tmp_arr[k++] = array[i++];    while(j <= high)        tmp_arr[k++] = array[j++];    i = low, k = 0;    while(i <= high)        array[i++] = tmp_arr[k++];}

1 0