八大排序算法(6) 快排序

基本思想

用分治的思想,在序列中选取一个基准数,把序列分成两个部分,一个部分比基准数小,一部分比基准数大,这样数列就被分成了两个部分,这两个部分间是有序的,然后就使用递归的思想,继续划分这两个部分,直到每个部分的数据个数都为1。

算法思路

 1. 假定将序列头作为基准数, 那么可以看成是将数列头提取出来的,需要在剩余的序列中找到一个数填进去。
 2. 要将序列分出两个部分,左边的小于基准数,右边的大于基准数
 3. 要保证 2 的话,则应该从右边开始遍历,找到第一个小于基准数的扔到左边去,找到的数的右边都是大于基准数的。此时可看成 右边 的部分少了一个大于基准数的数,那么就应该从左边开始遍历,找到第一个大于基准数的数扔到右边去,依次类推。如此可以保证左边、右边的部分都符合基本思路。
 4. 当分出的两个部分的序列大于 1 的时候,则再对每个序列进行依次快排序

示例:

// 升序,左起
/*初始值*/    3, 7, 5, 1, 2, 4, 9, 6, 10, 8

// 将 3 设为基准数,基准数是 第 1 个,从右边起找到第一个小于 3 的数、交换、记录其位置
/*第一趟*/    2, 7, 5, 1, 3, 4, 9, 6, 10, 8
// 基准数 是 第5个。此时 第5个 右边的数都比 3 大,然后从左起找第一个大于 3 的数、交换、记录其位置

/*第二趟*/    2, 3, 5, 1, 7, 4, 9, 6, 10, 8
// 基准数 是 第2个。此时,第2个 左边的数都比 3 小,第5个 右边的数都比3大。接下来从 第5个 起向左找第一个小于 3 的数、交换、记录其位置

/*第三趟*/    2, 1, 5, 3, 7, 4, 9, 6, 10, 8
// 基准数 是 第4个。此时,第2个 左边的数都比 3 小,第4个 右边的数都比3大。 接下来从 第2个 起向右找第一个大于 3 的数、交换、记录其位置

/*第四趟*/    2, 1, 3, 5, 7, 4, 9, 6, 10, 8
// 基准数 是 第3个。此时,第3个 左边的数都比 3 小,第4个 右边的数都比3大。 接下来从 第4个 起向右找第一个小于 3 的数、交换、记录其位置

// 此时,已顺利将序列 以第三个为界限 分为两个部分,左边的部分所有值、都比右边的部分小

重点:

如何高效的将序列分为小于/大于基准数的两个个部分。

思路:

 1. 在与基准数比较的时候,从右往左找到第一个小于基准数后,假设 index 为 m, 则此时 m 右边的值都是大于基准数的。此时,再将 m 与序列左边起第一个尚未与基准数比较过的位置交换,设该 index 为 n,即、将比基准数小的扔到了的左边。
 2. 此时,可以保证的是,m 、不包括m 、右边的都比基准数大,n、包括n、左边的都比基准数小, m为基准数。
 3. 下一个要找的数是 比基准数 大的,放在 m 的位置。
 4. 所以接下来,从 n 开始往右遍历,找到第一个比 基准数 大的,假设 index 为 n1,然后放到 m 的位置。
 5. 此时,可以保证的是, m 、包括m 、右边的都比基准数大, n1、不包括n1、左边的都比基准数小, n1 为基准数。
 6. 下一个要找的数是 比基准数 小的,放在 n1 的位置。
 7. 所以接下来,从 m 开始往左遍历,找到第一个比 基准数 大的,假设 index 为 m1,然后放到 n1 的位置。

代码:

void printList(int *l, int n) {
    for (int i = 0; i < n; i++) {
        printf("%d ", l[i]);
    }
    printf("\n");
}

void swap(int &m, int &n) {
    int j = m;
    m = n;
    n = j;
}

void quickSort(int l[], int lenth ) {
    if (lenth > 1) {
        int index = 0;
        // 升序 
        bool left = false;
        printf("\nquik sort start\n");
        printList(l, lenth);

        for (int i = 0, j = lenth - 1; i < j;) {
            printf("left: %d, i;%d, j:%d, index: %d\n", left, i, j, index);
            if ( left ) {
                // 从左往右 找第一个大于 l[index] 的
                if (l[i] > l[index]) {
                    swap(l[i], l[index]);
                    index = i;
                    // 变更遍历方向
                    left = false;
                    printList(l, lenth);
                }
                else {
                    i++;
                }
            } else {
                // 从右往左 找第一个小于 l[index] 的
                if ( l[j] < l[index]) {
                    swap(l[j], l[index]);
                    index = j;
                    // 变更遍历方向
                    left = true;
                    printList(l, lenth);

                }
                else {
                    j--;
                }
            }
        }

        printList(l, lenth);
        printf("quik sort end\n");

        // 迭代左边部分和右边部分
        quickSort(l, index);
        quickSort(l + index + 1, lenth - index - 1);
    }
}

int main()
{

    int a[10] = { 3,7,5,1,2,4,9,6,10,8 };
    printf("初始值:");
    printList(a, 10);

    quickSort(a, 10);

    printf("结果:");
    printList(a, 10);

    system("pause");
    return 0;
}

以上

原文链接 http://blog.csdn.net/u011546766/article/details/74055269

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值