标签:style blog http color ar 使用 for strong sp
每次比较数组中的两个数,如果和你期望的顺序不一致,就交换这两个数,一次循环下来能将一个数摆在正确的位置上。外层循环共需要N-1次,因为N-1个数都已经摆在正确的位置上,那第N个数也已经是正确的了。内层循环也可以是N-1次,也可以每次都比上一次少循环一次,第一种情况会比较已经排好序的部分,第二种情况已经排序过的部分不需要再比较了。还是两层循环都是N-1次比较好写。
void bubble_sort(int array[], int n)
{
    int i, j, temp;
    for ( i = 0; i < n - 1; i++ )
    {
        for ( j = 0; j < n - 1; j++ )
        {
            if ( array[j] > array[j+1] )
            {
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
    }
    return;
}
内层循环每次减少一次
void bubble_sort(int array[], int n)
{
    int i, j, temp;
    for ( i = 0; i < n - 1; i++ )
    {
        for ( j = 0; j < n - 1 - i; j++ )
        {
            if ( array[j] > array[j+1] )
            {
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
    }
    return;
}
在网上搜了几篇介绍快速排序的文章,个人感觉这篇《坐在马桶上看算法:快速排序》很不错,有图好理解。以下大部分内容均摘自此文章。
网址:http://developer.51cto.com/art/201403/430986.htm
快速排序的思想比较简单,整个排序过程分为三步:
待排序数组:6 1 2 7 9 3 4 5 10 8
1. 第一次选择最左边的6作为基准值
 
2. 从右边开始选择第一个小于6的数,下标递减,即j--
3. 从左边开始选择第一个大于6的数,下标递增,即i++
4. 交换这两个值,即交换7和5
      
      
5. 此时i != j,继续寻找
6. 第二次交换9和4
      
      
7. 再次寻找的话 i 就等于 j 了,这时交换基准值和array[i]
       
       
       
8. 这时6左边的数全部小于6,6右边的数全部大于6,接下来对这两个子序列进行同样的操作。
在写代码时要注意几个条件,开始扫描时,i必须总是小于j,i与j相等时则与基准值交换。另外,在递归调用时,判断low是否小于high,否则需要在quick_sort函数中对low和hign进行比较。
void quick_sort(int array[], int low, int high)
{
    int base = array[low];
    int i = low;
    int j = high;
    int temp;
    while ( i != j )
    {
        /* 从右侧寻找第一个小于基准值的数 */
        while ( array[j] >= base && i < j ) j--;
        /* 从左侧寻找第一个大于基准值的数 */
        while ( array[i] <= base && i < j ) i++;
        if ( i != j )
        {
            temp = array[j];
            array[j] = array[i];
            array[i] = temp;
        }
    }
    /* 此时i==j,和基准值交换 */
    array[low] = array[i];
    array[i] = base;
    /* 继续对两个子序列进行同样的操作 */
    if ( low < i - 1 )
        quick_sort(array, low, i-1);
    if ( i + 1 < high )
        quick_sort(array, i+1, high);
    return;
}
归并排序的核心思想是,将两个已经排序的子序列合并到一个序列中,时间复杂度为O(N)。如何得到有序的子序列呢?将整个序列进行二分,直到每个元素都是一个子序列。然后依次对每个子序列归并。分解过程采用递归的方式实现,时间复杂度为O(logN),所以归并排序的时间复杂度为O(NlogN).
void merge_array(int array[], int low, int mid, int high)
{
    int i = low, j = mid + 1;
    int m = mid, n = high;
    int k = 0;
    int *temp = new int[high-low+1];
    
    /* 将两个有序序列array[low...mid]和array[mid+1...high]合并*/
    while ( i <= m && j <= n )
    {
        if ( array[i] <= array[j] )
        {
            temp[k++] = array[i++];
        }
        else
        {
            temp[k++] = array[j++];
        }
    }
    /* 有一个序列会剩下,则将此序列的全部元素拷贝到临时数组中 */
    while ( i <= m ) 
    {
        temp[k++] = array[i++];
    }
    while ( j <= n )
    {
        temp[k++] = array[j++];
    }
    /* 拷贝回原始数组中 */
    for ( i = 0; i < k; i++ )
    {
        array[low+i] = temp[i];
    }
    delete [] temp;
    return;
}
void merge_sort(int array[], int low, int high)
{
    if ( low < high )
    {
        int mid = (low + high) / 2;
        //printf("%d %d %d\r\n", low, mid, high);
        merge_sort(array, low, mid);
        merge_sort(array, mid+1,high);
        merge_array(array, low, mid, high);
    }
    return;
}
本节内容来自http://www.cnblogs.com/zabery/archive/2011/07/26/2117103.html
堆分为大根堆和小根堆,是完全二叉树,大根堆的要求是每个节点的值都不大于其父节点的值,在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。首先需要把数组转换成堆,并调整堆符合大根堆的要求。请看下图,数组为A = {1, 3, 4, 5, 7, 2, 6, 8, 0}

操作步骤
1. 数组A转换成堆为图1.1的形式,父节点的左叶子节点为 2*i+1, 右叶子节点是 2*i+2,i从0开始
2. 调堆的过程从最后一个非叶子节点开始,从图1.1可以看出,最后一个非叶子节点是A[3]=5
    如果数组有奇数个,则最后一个非叶子节点拥有两个孩子,即最后一个非叶子节点的右孩子为数组的最后一个值,则如下表达式成立 2*i+2 = n-1,得出i=(n-3)/2
    如果数组有偶数个,则最后一个非叶子节点拥有左孩子,这个左孩子为数组的最后一个值,2*i+1 = n-1,得出i=(n-2)/2
    由于除号只保留整数部分,所以这两个表达式计算得出的i是相等的,下面的代码中,我们把(n-2)/2作为最后一个非叶子节点
3. 图1.4与图1.3对比,3与8交换,此时3小于其左孩子5,所以3和5也要交换,得出图1.5. 图1.6到图1.7也有两次交换,所以调整堆时要注意大根堆的定义,即每个节点的值都不大于其父节点的值。要循环判断直到符合要求。
4. 每次调整堆结束后,堆的第一个元素都是当前堆的最大值,然后将此元素与堆的最后一个元素交换,堆元素的个数减一,继续调整堆,交换堆首元素与堆的最后一个元素,如此反复,直到堆的元素个数还剩1,排序完成
/* 
    n:元素个数
    i:需要比较的子树的根节点
*/
void adjust_heap(int array[], int n, int i)
{
    int    left  = 2 * i + 1;
    int right = 2 * i + 2;
    int largest = i;
    int temp;
    while ( left < n || right < n )
    {
        /* 找到根节点和两个叶子节点中最大的值 */
        if ( left < n && array[largest] < array[left] )
        {
            largest = left;
        }
        if ( right < n && array[largest] < array[right] )
        {
            largest = right;
        }
        /* 如果根节点不是最大值,则与最大值交换 */
        if ( largest != i )
        {
            temp = array[largest];
            array[largest] = array[i];
            array[i] = temp;
            /* 操作步骤3的实现,循环比较整个子树是否符合要求 */
            i = largest;
            left  = 2 * i + 1;
            right = 2 * i + 2;
        }
        else
        {
            break;
        }
    }
    return;
}
void build_heap(int array[], int n)
{
    int i;
    /* 操作步骤2的实现,从最后一个非叶子节点开始调整堆,直到根节点 */
    for ( i = (n - 2)/2; i >= 0; i-- )
    {
        adjust_heap(array, n, i);
    }
    return;
}
void heap_sort(int array[], int n)
{
    int i, temp;
    
    build_heap(array, n);
    /* 步骤4的实现,每次循环交换堆的第一个元素与最后一个元素,堆大小每次减1,
       由于每次调整堆,堆的第一个元素都是当前堆的最大值,交换后就得到一个排
       好序的数组 */
    for ( i = n - 1; i > 0; i-- )
    {
        temp = array[0];
        array[0] = array[i];
        array[i] = temp;
        adjust_heap(array, i, 0);
    }
    return;
}
标签:style blog http color ar 使用 for strong sp
原文地址:http://www.cnblogs.com/lifehack/p/3978101.html