快速排序及算法实现

快速排序及算法实现

快速排序(Quick Sort) 是对冒泡排序的一种改进方法,在冒泡排序中,进行元素的比较和交换是在相邻元素之间进行的,元素每次交换只能移动一个位置,所以比较次数和移动次数较多,效率相对较低。而在快速排序中,元素的比较和交换是从两端向中间进行的,较大的元素一轮就能够交换到后面的位置,而较小的元素一轮就能交换到前面的位置,元素每次移动的距离较远,所以比较次数和移动次数较少,速度较快,故称为“快速排序”。

快速排序的基本思想是:通过一轮排序将待排序元素分割成独立的两部分, 其中一部分的所有元素均比另一部分的所有元素小,然后分别对这两部分的元素继续进行快速排序,以此达到整个序列变成有序序列。快速排序的最坏时间复杂度为O(n2),平均时间复杂度为O(n*log2n)
算法介绍编辑
快排图
快排图
设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],将A[j]的值赋给A[i];
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]的值赋给A[j];
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
排序演示编辑
示例假设用户输入了如下数组:下标0 1  2 3 4 5数据627389创建变量i=0(指向第一个数据), j=5(指向最后一个数据), k=6(赋值为第一个数据的值)。我们要把所有比k小的数移动到k的左面,所以我们可以开始寻找比6小的数,从j开始,从右往左找,不断递减变量j的值,我们找到第一个下标3的数据比6小,于是把数据3移到下标0的位置,把下标0的数据6移到下标3,完成第一次比较:下标0123	45数据327689i=0 j=3 k=6接着,开始第二次比较,这次要变成找比k大的了,而且要从前往后找了。递加变量i,发现下标2的数据是第一个比k大的,于是用下标2的数据7和j指向的下标3的数据的6做交换,数据状态变成下表:下标012345数据326789i=2 j=3 k=6称上面两次比较为一个循环。接着,再递减变量j,不断重复进行上面的循环比较。在本例中,我们进行一次循环,就发现i和j“碰头”了:他们都指向了下标2。于是,第一遍比较结束。得到结果如下,凡是k(=6)左边的数都比它小,凡是k右边的数都比它大:下标012345数据326789如果i和j没有碰头的话,就递加i找大的,还没有,就再递减j找小的,如此反复,不断循环。注意判断和寻找是同时进行的。然后,对k两边的数据,再分组分别进行上述的过程,直到不能再分组为止。注意:第一遍快速排序不会直接得到最终结果,只会把比k大和比k小的数分到k的两边。为了得到最后结果,需要再次对下标2两边的数组分别执行此步骤,然后再分解数组,直到数组不能再分解为止(只有一个数据),才能得到正确结果。2-1、示意图

2-2、代码
快速排序算法的代码实现:

QuickSort.java

public class QuickSort {
public static void main(String[] args) {
int[] list = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8};
System.out.println(“快速排序”);
System.out.println(“排序前:”);
display(list);

    System.out.println("排序后:");
    quickSort(list, 0, list.length - 1);
    display(list);
}

/**
 * 快速排序算法
 */
public static void quickSort(int[] list, int left, int right) {
    if (left < right) {
        // 分割数组,找到分割点
        int point = partition(list, left, right);

        // 递归调用,对左子数组进行快速排序
        quickSort(list, left, point - 1);
        // 递归调用,对右子数组进行快速排序
        quickSort(list, point + 1, right);
    }
}

/**
 * 分割数组,找到分割点
 */
public static int partition(int[] list, int left, int right) {
    // 用数组的第一个元素作为基准数
    int first = list[left];
    while (left < right) {
        while (left < right && list[right] >= first) {
            right--;
        }
        // 交换
        swap(list, left, right);

        while (left < right && list[left] <= first) {
            left++;
        }
        // 交换
        swap(list, left, right);
    }
    // 返回分割点所在的位置
    return left;
}

/**
 * 交换数组中两个位置的元素
 */
public static void swap(int[] list, int left, int right) {
    int temp;
    if (list != null && list.length > 0) {
        temp = list[left];
        list[left] = list[right];
        list[right] = temp;
    }
}

/**
 * 遍历打印
 */
public static void display(int[] list) {
    System.out.println("********展示开始********");
    if (list != null && list.length > 0) {
        for (int num :
                list) {
            System.out.print(num + " ");
        }
        System.out.println("");
    }
    System.out.println("********展示结束********");
}

}

测试结果:

3、冒泡排序VS快速排序
代码如下:

BubbleVsQuick.java

public class BubbleVsQuick {

public static void main(String[] args) {
    testQuick();
    testBubble();
}

/**
 * 测试快速排序耗费的时间
 */
public static void testQuick() {
    int[] list = new int[10000];
    for (int i = 0; i < 10000; i++) {
        list[i] = (int) (Math.random() * 100000);
    }

    // 快速排序
    long start = System.currentTimeMillis();
    QuickSort.quickSort(list, 0, list.length - 1);
    long end = System.currentTimeMillis();
    System.out.println("快速排序耗费的时间:" + (end - start));
    display(list);
}

/**
 * 测试冒泡排序耗费的时间
 */
public static void testBubble() {
    int[] list = new int[10000];
    for (int i = 0; i < 10000; i++) {
        list[i] = (int) (Math.random() * 100000);
    }

    // 冒泡排序
    long start = System.currentTimeMillis();
    BubbleSort.bubbleSort(list);
    long end = System.currentTimeMillis();
    System.out.println("冒泡排序耗费的时间:" + (end - start));
    display(list);
}

/**
 * 遍历打印前10个数
 */
public static void display(int[] list) {
    System.out.println("********排序之后的前10个数start********");
    if (list != null && list.length > 0) {
        for (int i = 0; i < 10; i++) {
            System.out.print(list[i] + " ");
        }
        System.out.println("");
    }
    System.out.println("********排序之后的前10个数end**********");
    System.out.println("");
}

}

测试结果:

可见,快速排序的速度比冒泡排序更快。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mr xk_f

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值