快速排序(用递归实现)

什么是递归?

递归:无限调用自身这个函数,每次调用总会改动一个关键变量,直到这个关键变量达到边界的时候,不再调用。

递归与循环的区别于联系

相同点: 
(1)都是通过控制一个变量的边界(或者多个),来改变多个变量为了得到所需要的值,而反复而执行的; 
(2)都是按照预先设计好的推断实现某一个值求取;(请注意,在这里循环要更注重过程,而递归偏结果一点)

不同点: 

(1)递归通常是逆向思维居多,“递”和“归”不一定容易发现(比较难以理解);而循环从开始条件到结束条件,包括中间循环变量,都需要表达出来(比较简洁明了)。

简单的来说就是:用循环能实现的,递归一般可以实现,但是能用递归实现的,循环不一定能。因为有些题目①只注重循环的结束条件和循环过程,而往往这个结束条件不易表达(也就是说用循环并不好写);②只注重循环的次数而不注重循环的开始条件和结束条件(这个循环更加无从下手了)。

快速排序

快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

排序方法:

1、先从数列中选取一个基准数,一般为了方便就选第一个。

2、再对数组进行排序,大的在右边,小的在左边。

3、再分别对左右边重复第一二步,直到各区间只剩下一个数。

 

来个实例:

以一个数组为例,取第一个数为基准

 

 

0123456789
26214565107849891332

 

初始化值,int i=0,j=9,x=a[0];把a[0]赋给x(基准数),相当于给a[0]的位置挖了个坑,把a[0]保存给x以后再用。

先从右即j=9开始循环找出比x小的数,循环到j=8时,a[8]>x,我们就要用a[8]填上a[0]这个坑,a[0]=a[8];   i++;,这时候a[0]的坑填上了但a[8]位置又变成了坑,我们就要从左边进行i循环找到一个比x大的数来填补a[8]这个坑。i++;循环过后,发现a[2]比x大,则a[8]=a[2];  j--;

数组变成了:

 

 

0123456789
13214565107849894532

 

这时,i=2,j=7,x=26。

然后继续重复上述步骤,直到i==j;再将基准数x填入a[i];然后对左右两个子区间进行递归排序,直到区间大小为1时停止。

 

我们来实现一下代码:

public static void sort(int a[], int low, int hight) {
        int i, j, index;
        if (low > hight) {
            return;
        }
        i = low;
        j = hight;
        index = a[i]; // 用子表的第一个记录做基准
        while (i < j) { // 从表的两端交替向中间扫描
            while (i < j && a[j] >= index)
                j--;
            if (i < j)
                a[i++] = a[j];// 用比基准小的记录替换低位记录
            while (i < j && a[i] < index)
                i++;
            if (i < j) // 用比基准大的记录替换高位记录
                a[j--] = a[i];
        }
        a[i] = index;// 将基准数值替换回 a[i]
        sort(a, low, i - 1); // 对低子表进行递归排序
        sort(a, i + 1, hight); // 对高子表进行递归排序

    }

快速排序的优化

对于基准位置的选取一般有三种方法:固定切分,随机切分和三取样切分。固定切分的效率并不是太好,随机切分是常用的一种切分,效率比较高,最坏情况下时间复杂度有可能为O(N2).对于三数取中选择基准点是最理想的一种。

三数取中切分:

public static int partition(int []array,int lo,int hi){
        //三数取中
        int mid=lo+(hi-lo)/2;
        if(array[mid]>array[hi]){
            swap(array[mid],array[hi]);
        }
        if(array[lo]>array[hi]){
            swap(array[lo],array[hi]);
        }
        if(array[mid]>array[lo]){
            swap(array[mid],array[lo]);
        }
        int key=array[lo];
        
        while(lo<hi){
            while(array[hi]>=key&&hi>lo){
                hi--;
            }
            array[lo]=array[hi];
            while(array[lo]<=key&&hi>lo){
                lo++;
            }
            array[hi]=array[lo];
        }
        array[hi]=key;
        return hi;
    }
    
    public static void swap(int a,int b){
        int temp=a;
        a=b;
        b=temp;
    }
    public static void sort(int[] array,int lo ,int hi){
        if(lo>=hi){
            return ;
        }
        int index=partition(array,lo,hi);
        sort(array,lo,index-1);
        sort(array,index+1,hi);
    }

快速排序在序列中元素很少时,效率将比较低,不然插入排序,因此一般在序列中元素很少时使用插入排序,这样可以提高整体效率。

public static void quick(int []array ,int lo,int hi){
        if(hi-lo+1<10){
            insertSort(array);
        }else{
            quickSort(array,lo,hi);
        }
    }

 

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 JavaScript 编写的记忆游戏(附源代码)   项目:JavaScript 记忆游戏(附源代码) 记忆检查游戏是一个使用 HTML5、CSS 和 JavaScript 开发的简单项目。这个游戏是关于测试你的短期 记忆技能。玩这个游戏 时,一系列图像会出现在一个盒子形状的区域中 。玩家必须找到两个相同的图像并单击它们以使它们消失。 如何运行游戏? 记忆游戏项目仅包含 HTML、CSS 和 JavaScript。谈到此游戏的功能,用户必须单击两个相同的图像才能使它们消失。 点击卡片或按下键盘键,通过 2 乘 2 旋转来重建鸟儿对,并发现隐藏在下面的图像! 如果翻开的牌面相同(一对),您就赢了,并且该对牌将从游戏中消失! 否则,卡片会自动翻面朝下,您需要重新尝试! 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox, 以获得更好、更优化的游戏体验。要玩游戏,首先,通过单击 memorygame-index.html 文件在浏览器中打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
快速排序是一种常用的排序算法,它通过递归地将数组分成较小和较大的两个子数组来实现排序。下面是快速排序的C语言递归实现: ```c #include <stdio.h> // 交换两个元素的值 void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } // 将数组分成两部分,并返回分割点的索引 int partition(int arr[], int low, int high) { int pivot = arr[high]; // 选取最后一个元素作为基准值 int i = (low - 1); // 记录小于基准值的元素的索引 for (int j = low; j <= high - 1; j++) { // 如果当前元素小于等于基准值,则将其与小于基准值的元素交换位置 if (arr[j] <= pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); // 将基准值放到正确的位置上 return (i + 1); // 返回分割点的索引 } // 快速排序递归函数 void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); // 获取分割点的索引 // 对分割点左边的子数组进行递归排序 quickSort(arr, low, pi - 1); // 对分割点右边的子数组进行递归排序 quickSort(arr, pi + 1, high); } } // 打印数组 void printArray(int arr[], int size) { for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); } int main() { int arr[] = {64, 25, 12, 22, 11}; int n = sizeof(arr) / sizeof(arr); printf("原始数组:\n"); printArray(arr, n); quickSort(arr, 0, n - 1); printf("排序后的数组:\n"); printArray(arr, n); return 0; } ``` 这段代码实现快速排序算法的递归版本。首先定义了一个`swap`函数用于交换两个元素的值。然后定义了`partition`函数,它选择最后一个元素作为基准值,将数组分成两部分,并返回分割点的索引。接下来是`quickSort`函数,它通过递归调用自身来对分割点左右两个子数组进行排序。最后,在`main`函数中测试了快速排序算法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值