码迷,mamicode.com
首页 > 其他好文 > 详细

排序算法

时间:2014-07-28 00:02:29      阅读:370      评论:0      收藏:0      [点我收藏+]

标签:希尔排序   快速排序   归并排序   排序算法   堆排序   

总结

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

冒泡排序                       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++];

}

排序算法,布布扣,bubuko.com

排序算法

标签:希尔排序   快速排序   归并排序   排序算法   堆排序   

原文地址:http://blog.csdn.net/shutingchen/article/details/38173361

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!