快速查找算法学习笔记(Java)

快速查找算法学习笔记(Java)

一、实现思路

1.寻找一个位于数列中部的数字,记为pivot。

2.分别在目标数段的左端和右端开始遍历,在左方,寻找值大于或等于pivot的数字,在右方,寻找值小于或等于pivot的数字,并且依此交换。

3.完成一轮交换后,在pivot的左方应为无序但都小于pivot的数字段,右方同理。

4.使用递归,分别在pivot的左方和右方再次调用快速查找的方法。

二、代码实现

 public void quickSort(int[] arr, int left, int right) {
        int l = left; //左方开始的点
        int r = right; //右方开始的点
        int pivot =arr[(left + right) / 2]; //中间值
        int temp; //临时变量,用于数列不同位置交换数值
        while (l < r) { //当左点小于右点时,意味着数列未遍历完毕,继续执行代码。
            while (arr[l] < pivot) {
                l++;  //左方数值小于pivot,继续遍历。大于pivot,跳出循环,arr[l]即为需要交换的数值
            }
            while (arr[r] > pivot) {
                r--;  //同理
            }
            if (l >= r) break; //满足此条件需要及时跳出循环,以免执行后续代码可能导致越界访问数组报错。
            temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp; //交换符合需求的数值
            if (arr[r] == pivot) l++;
            if (arr[l] == pivot) r--; //防止出现死循环(下面详谈)
		}
        if (r == l) {
            r--;
            l++;
        } //防止出现死递归导致栈溢出
        if (left < r) {
            quickSort(arr, left, r);
        }
        if (l < right) {
            quickSort(arr, l, right);
        } //不满足条件则退出递归,满足条件则再次调用方法。
    }

三、代码分析

1.防止出现死循环或排序不准的代码块

{
 if (arr[r] == pivot) l++;
 if (arr[l] == pivot) r--;
}

如果没有这段代码,程序可能会出现死循环。假如遇到[…, 11, …, 11, …]此形式的数组,且pivot值恰为11,左右数值在遍历到左右端的11时,会触发条件进行交换。交换后仍满足交换条件,便会再次进行交换,进入死循环。
(学习误区记录:初学时错误认为只有当两边都等于pivot值时才会发生死循环,而这段代码一读到与pivot数值相同的数字就会执行,认为没有必要,将代码改为:

if (arr[r] == arr[l] && arr[r] == pivot) {
	l++;
	r--;
	}

这样虽然能避免死循环,但是可能会出现排序错乱的情况。比如数组[…, 11, 8, 7, 11, …], pivot为11,当左右两端恰好都读到11时,执行上述代码,虽然能避免死循环,但是左右端分别指向8和7,并且后续不会进行交换,显然错误。

2.防止死递归导致栈溢出的代码块

if (r == l) {
	r--;
    l++;
} 

如果没有此代码块,在递归过程中不会有影响。但是会影响递归结束判断,造成死递归。比如在递归到数组[1, 2]部分, left = 0, right = 1, pivot = 1, 当左右点在1处相遇时,结束遍历,也应当结束递归,如果缺少上述代码块,l < right 条件仍然成立, 又会执行quickSort(arr, l, right);并且下一次执行的数组也是left = 0, right = 1, pivot = 1,所以会死递归导致栈溢出。

3.防止出现越界访问数组报错的代码块

if (l >= r) break; 

如果没有此代码块,可能会出现越界访问数组报错。比如[…, 11] ,且pivot恰好为11,右点指向此11时, 若恰好左点也指向数组末尾的同一11,此时应当执行上述代码块跳出循环。若没有上诉代码块,满足arr[r] == pivot的条件,则会执行代码l++, 此时l的值就会超出数组范围,当再次进入循环执行判断语句arr[l] < pivot时,便会越界访问数组,进行报错。

此次学习的视频:
【尚硅谷】数据结构与算法(Java数据结构与算法) (66 ~ 68)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值