高级排序:快速排序

一.概述
快速排序是对冒泡排序的一种改进。
基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

二.原理
1.首先设定一个分界值(默认为第一个数),通过该分界值将数组分成左右两部分;
2.将大于或等于分界值的数据放到到数组右边,小于分界值的数据放到数组的左边。此时左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值;
3.然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
4.重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左侧和右侧两个部分的数据排完序后,整个数组的排序也就完成了。

在这里插入图片描述
具体的切分过程:
1.找一个基准值(默认为第一个元素),用两个指针分别指向数组的头部和尾部;
2.先从右向左开始搜索一个比基准值的元素,搜索到即停止,并记录指针的位置;
3.再从左向右开始搜索一个比基准值的元素,搜索到即停止,并记录指针的位置;
4.交换当前左边指针位置和右边指针位置的元素;
5.重复2,3,4步骤,直到左边指针的值大于右边指针的值停止。

例:
设定基准值,并准备两个指针,left指针指向分界值所在的索引lo处,right指针指向hi+1。
思路:right指针从右往左走,找到比6小的元素;然后left从左往右走,找到比6大的元素(双向排查),而后两数交换。
在这里插入图片描述
第一次,right指针左移一位,指向8,8>6,不满足。再左移来到5,5<6,满足,指针暂停在5处。
同理,left指针右移,寻找比6大的元素,依次移到 1 2 都不满足,直到指向7,7>6,满足条件。
在这里插入图片描述
交换right指针指向的“5”和left指针指向的“7”。
在这里插入图片描述
将两个指针指向的元素交换之后,right指针继续左移找到4<6,然后left左移找到9>6,交换4和9。在这里插入图片描述Again,right指针左移找到3<6,指针停在3。left指针右移到3也就是right指针的位置,此时满足条件 (left>=right) ,left和right指针重合,即代表此时两个指针扫描完毕,这时交换分界值6 和两个指针共同指向的值3。在这里插入图片描述
到此这一数组的切分完成,然后以分界值为界,将其分为两个数组,再重复以上步骤。
在这里插入图片描述

三.Java代码实现

public class quick {
    public static void sort(int[] a){
        int lo=0;
        int hi=a.length-1;
        sort(a,lo,hi);

    }

    public static void sort(int[]a,int lo,int hi){
    if(lo>=hi){//安全校验,即递归出口
        return;
    }	//前序遍历 
        int partition=partition(a,lo,hi); //排序并返回分界值交换后的索引
        //先排序,再切分! 即前序遍历
        sort(a,lo,partition-1);
        sort(a,partition+1,hi);
    }

    private static int partition(int[] a, int lo, int hi) {
        //确定分界值
        int key=a[lo];
        //定义两个指针,分别指向分界值的索引处和最大索引处下一位
        int left=lo;
        int right=hi+1;
        //切分
        while(true) {
            //先右
            while (a[--right]>key) {//找的是right < key ,循环条件相反。
                if(right==lo){
                    break;}   // 越界,跳出while
                }
            //后左
            while(a[++left]<key){ //找的是left>key,循环条件相反
                if(left==hi){
                    break;   // 越界,跳出while
                }
            }
            if(left>=right){ //指针重合,跳出最外层循环
                break;
            }else{ //指针还未重合,则交换左、右指针处元素
                swap(a,left,right);
            }
        }
        swap(a,lo,right); //最后交换分界值和重合处元素
        return right; //返回分界值交换后的索引
    }

    public static void swap(int[] a,int lo,int hi){
     int k=a[lo];
     a[lo]=a[hi];
     a[hi]=k;
    }
    
    public static void main(String[] args) {
        int[]a={6, 1, 2, 7, 9, 3, 4, 5, 8};
        sort(a);
        System.out.println(Arrays.toString(a));
    }
}

运行结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

注意:

  1. 快速排序是先排序!并返回一个分界值的索引 int值,再进行递归,当递归到最后时,数组已经排序完成(分组的过程中就已经排序了,分完组的时候也就排好序了);
    归并排序是先使用递归来分组,分组完成后 再调用merge进行归并排序。(自底向上,分组完之后才开始依次使用merge进行归并)

  2. 判断左右指针是否重合的条件必须是if(left>=right){ break;}
    而不能是if(left==right){ break;} 。因为左右指针都在移动,如果使用left==right来判断有可能错开。

  3. partition 返回的必须是right ,不能是left !

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是使用pthread线程池实现快速排序并计时的C代码: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sys/time.h> #define THREAD_NUM 8 #define ARRAY_SIZE 10000000 typedef struct { int *arr; int left; int right; } quicksort_args_t; typedef struct { quicksort_args_t *args; pthread_t thread; } worker_t; typedef struct { worker_t *workers; int worker_num; pthread_mutex_t mutex; pthread_cond_t cond; int task_count; int task_index; int done; } thread_pool_t; void init_thread_pool(thread_pool_t *pool, int worker_num); void submit_task(thread_pool_t *pool, quicksort_args_t *args); void join_thread_pool(thread_pool_t *pool); void *worker(void *args); void quicksort(int *arr, int left, int right); int partition(int *arr, int left, int right); void swap(int *a, int *b); void print_array(int *arr, int size); double get_time(); int main() { int *arr = (int *)malloc(ARRAY_SIZE * sizeof(int)); for (int i = 0; i < ARRAY_SIZE; i++) { arr[i] = rand() % 1000000; } double start_time = get_time(); thread_pool_t pool; init_thread_pool(&pool, THREAD_NUM); quicksort_args_t args = { .arr = arr, .left = 0, .right = ARRAY_SIZE - 1 }; submit_task(&pool, &args); join_thread_pool(&pool); double end_time = get_time(); printf("Sorted array:\n"); print_array(arr, ARRAY_SIZE); printf("Time elapsed: %f seconds\n", end_time - start_time); free(arr); return 0; } void init_thread_pool(thread_pool_t *pool, int worker_num) { pool->worker_num = worker_num; pool->workers = (worker_t *)malloc(worker_num * sizeof(worker_t)); pool->task_count = 0; pool->task_index = 0; pool->done = 0; pthread_mutex_init(&pool->mutex, NULL); pthread_cond_init(&pool->cond, NULL); for (int i = 0; i < worker_num; i++) { pool->workers[i].args = NULL; pthread_create(&pool->workers[i].thread, NULL, worker, pool); } } void submit_task(thread_pool_t *pool, quicksort_args_t *args) { pthread_mutex_lock(&pool->mutex); pool->task_count++; pool->workers[pool->task_index].args = args; pool->task_index = (pool->task_index + 1) % pool->worker_num; pthread_cond_signal(&pool->cond); pthread_mutex_unlock(&pool->mutex); } void join_thread_pool(thread_pool_t *pool) { pthread_mutex_lock(&pool->mutex); while (pool->done == 0) { pthread_cond_wait(&pool->cond, &pool->mutex); } pthread_mutex_unlock(&pool->mutex); } void *worker(void *args) { thread_pool_t *pool = (thread_pool_t *)args; while (1) { pthread_mutex_lock(&pool->mutex); while (pool->task_count == 0 && pool->done == 0) { pthread_cond_wait(&pool->cond, &pool->mutex); } if (pool->done == 1) { pthread_mutex_unlock(&pool->mutex); break; } quicksort_args_t *task_args = pool->workers[pool->task_index].args; pool->task_index = (pool->task_index + 1) % pool->worker_num; pool->task_count--; pthread_mutex_unlock(&pool->mutex); quicksort(task_args->arr, task_args->left, task_args->right); free(task_args); if (pool->task_count == 0) { pthread_mutex_lock(&pool->mutex); if (pool->task_count == 0) { pool->done = 1; pthread_cond_signal(&pool->cond); } pthread_mutex_unlock(&pool->mutex); } } return NULL; } void quicksort(int *arr, int left, int right) { if (left >= right) { return; } int pivot = partition(arr, left, right); quicksort(arr, left, pivot - 1); quicksort(arr, pivot + 1, right); } int partition(int *arr, int left, int right) { int pivot = arr[right]; int i = left - 1; for (int j = left; j < right; j++) { if (arr[j] < pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[right]); return i + 1; } void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } void print_array(int *arr, int size) { for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); } double get_time() { struct timeval tv; gettimeofday(&tv, NULL); return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; } ``` 首先在`init_thread_pool`函数中初始化线程池,创建`worker_num`个线程,并将其保存在`pool->workers`数组中。每个线程将执行`worker`函数。 在`submit_task`函数中,我们将任务加入到线程池中。我们使用一个循环数组来记录每个线程的任务,每次调用`submit_task`时,我们将任务保存在下一个线程的任务数组中。`task_count`变量记录了任务数目,`task_index`变量记录了下一个将要保存任务的线程的索引。 在`join_thread_pool`函数中,我们等待所有线程完成任务。`done`变量表示线程池的所有任务是否已经完成。 `worker`函数是每个线程执行的函数。它使用`pthread_cond_wait`函数等待任务,直到线程池中有任务可以执行。然后它获取下一个任务,执行任务,并释放任务的内存。当线程池中没有任务时,它会等待一个信号,直到有新的任务进入线程池或者线程池的所有任务都已经完成。 `quicksort`和`partition`函数是快速排序的实现。`swap`函数用于交换数组中的两个元素。 `print_array`函数用于打印数组。 `get_time`函数用于获取当前时间,用于计算排序的时间。 我们可以在`main`函数中调用`init_thread_pool`函数初始化线程池,创建一个包含`ARRAY_SIZE`个元素的随机整数数组,并将其传递给`quicksort`函数。然后我们调用`submit_task`函数将任务提交到线程池中,并调用`join_thread_pool`函数等待线程池中的所有任务完成。最后我们打印排序后的数组,并计算排序所花费的时间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值