排序

1.  排序的几个概念

     (1)内部排序与外部排序:

               整个过程都在内存中进行,则叫内部排序;否则为外部排序。

     (2)主关键字和次关键字:

               若排序过程中主关键字相同,则使用次关键字进行比较。

     (3)排序的稳定性:

               若排序前Ki  = Kj (i < j),排序后仍然如此,则稳定;否则不稳定。

2.  算法实例

     2.1  直接插入排序:在已排好序的集合上继续插入一个元素构成新的集合。

            部分代码(完整代码直接插入.c):

 

void insert_sort (RecordType *r, int l)
{
    /* 数组元素 r[0]是监视哨 */
    int     i, j;
    for (i = 2; i <= l; i++) {
        r[0] = r[i];
        /* 从后向前比较,边比较边移动 */
        for (j = i-1; r[0].key < r[j].key; j--) 
            r[j+1] = r[j];
        r[j+1] = r[0];
    }
}
           时空复杂度:T(n) = O(n2), S(n) = O(1)


    2.2  折半插入排序:利用折半的思想在 {1...i-1} 中查找 i 的位置

            部分代码(完整代码折半插入.c):

void insert_sort (RecordType *r, int l) 
{
    /* 数组元素 r[0]是监视哨 */
    int     i, j;
    int     low, high, mid;

    for (i = 2; i <= l; i++) {
        r[0] = r[i];

        low = 1, high = i - 1;
        while (low <= high) {
            mid = (low + high)/2;
            if (r[0].key < r[mid].key) 
                high = mid-1;
            else 
                low = mid + 1;
        }

        for (j = i-1; j >= low; j--) 
            r[j+1] = r[j];
        r[low] = r[0];
    }
}
           时空复杂度:T(n) = O(n2), S(n) = O(1)

     2.3  shell排序:分组,组内进行直接插入排序的思想,多次重复减小组内间距

             部分代码(完整代码shell排序.c

void shell_insert (int r[], int l, int delta)
{
    int     i, j;
    for (i = 1+delta; i <= l; i++) {
        if (r[i] < r[i-delta]) {
            r[0] = r[i];

            // 组内进行直接插入排序
            for (j = i-delta; j > 0 && r[0] < r[j]; j-=delta) 
                r[j+delta] = r[j];
            r[j+delta] = r[0];
        }
    }
}

void shell_sort (int r[], int l, int delta[], int n)
{
    int     i;
    for (i = 0; i < n; i++) {
        shell_insert (r, l, delta[i]);
    }
}

           时间复杂度:T(n) = O(n1.5)


     2.4  冒泡排序:第 i 趟对前前 n-i 个元素进行相邻节点比较,若在某一趟中没有发现一个逆序,则可以终止比较

             部分代码(完整代码bubble.c

#define SWAP(x, y, type) \
    {type    __swap_; \
     __swap_ = x; \
     x = y; \
     y = __swap_;}

void bubble_sort (int r[], int l)
{
    int     i, j; 
    int     t; 
    unsigned char   change = TRUE;

    for (i = 0; i < l && change; i++) {

        change = FALSE;
        for (j = 0; j < l-i-1; j++) 
            if (r[j] > r[j+1]) { 
                SWAP (r[j], r[j+1], int);
                change = TRUE;
            } 
     }
}


     2.5  快速排序:快排是对冒泡的一种改进,将轴从到辅助单元中,以轴为中心从左右两边开始比较,如右边碰到比轴小的则放到low里边,若左边碰到比轴大的则放到hegh里边直到low >= high, 一趟结束,如此重复左边和右边的记录

             部分代码(完整代码QKSort.c

void QK_sort (int r[], int low, int high)
{
    if (low < high) {
        int pos = QK_pass (r, low, high);
        QK_sort (r, low, pos-1);
        QK_sort (r, pos+1, high);
    }
}

int QK_pass (int r[], int low, int high)
{
    int x = r[low];

    while (low < high) {
        // 从右向左找小于x的元素
        while (low < high && r[high] >= x) 
            high--;
        // 找到小的送入low单元
        if (low < high) 
            r[low++] = r[high];

        // 从左向右找大于等于x的元素
        while (low < high && r[low] < x) 
            low++;
        // 找到大的送入high单元
        if (low < high) 
            r[high--] = r[low];
    }

    // 插入基准到 low = high单元
    r[low] = x;
    // 返回基准位置
    return low;
}


     2.6  选择排序:在i+1到n这段记录中找到小于i的且最小的和i进行交换,完成一趟,如此重复

             部分代码(完整代码selectSort.c

void select_sort (int r[], int n)
{
    int     i, j;

    for (i = 0; i < n; i++) { 
        int     k = i; 
        for (j = i+1; j < n; j++) {
            // 记录k的位置,k是j到n-1小于i且最小的
            if (r[j] < r[k]) 
                k = j;

            // 如果有这样的k则替换
            if (k != i)
                SWAP (r[i], r[k], int);
        }
    }
}

     2.6  堆排序排序:sift函数创建大根堆,然后在排序时将根和堆尾交换,堆尾移出,重建大根堆重复

             部分代码(完整代码heapSort.c

void sift (int r[], int k, int m)
{
    int t = r[k];
    int i = k;
    int j = 2*i;
    unsigned char   finished = FALSE;

    while (j <= m && !finished) {
        // 找到i的孩子中最大的孩子
        if (j < m && r[j] < r[j+1]) 
            j++;
        // 根比孩子都大,则结束
        if (t >= r[j]) 
            finished = TRUE;
        else {
            // 否则上移,继续比较
            r[i] = r[j];
            i = j;
            j = 2*i;
        }
    }
    r[i] = t;
}

void crt_heap (int r[], int l)
{
    int i;
    for (i = l/2; i >= 1; i--)
        // 自第Ln/2」个记录开始重建堆
        sift (r, i, l);
}

void heap_sort (int r[], int l)
{
    crt_heap (r, l);
    int i;

    for (i = l; i >= 2; i--) {
        // 存放堆尾
        int b = r[1];
        // 堆尾放到堆首
        r[1] = r[i];
        // 将b,将根存放到堆尾
        r[i] = b;
        // 重建堆
        sift (r, 1, i-1);
    }
}
</pre><pre code_snippet_id="254386" snippet_file_name="blog_20140325_8_8485226" name="code" class="plain">
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值