《算法设计与分析》 实验4

整数二分解析

在这里插入图片描述
用二分的思想可以找出这个分界点。
假设我们想二分出来红色(不满足条件的范围)这边的分界点:

  1. 找一个中间值mid :l+r >> 1
  2. 写一个函数check()判断时mid时在满足条件(绿色)范围内,还是在不满足条件(红色)范围内。
  3. (注意:这里为什么是 l+r+1 )
    For example:
    如果 l = r - 1 (即左右边界只相差1) ,假设为l+r >> 1 (向下取整)假设if(check(mid)) 判断为true (此时mid = l + r >> 1 == l)则执行l=mid; l=mid=l;陷入死循环,左右边界一直为[l, r] 没有变
    如果是l+r+1>>1则不会发生这个问题(详情自己参考上面推导一遍即可)。
    在这里插入图片描述

两个整数二分模板

//模板1
/———————————————————————————————— 整数二分模板1 ————————————————————————————————\
static boolean check(int x) {/* ... */ } // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
public static int bsearch_1(int l, int r) {
	while (l < r) {
		int mid = l + r >> 1;
		if (check(mid)) r = mid;    // check()判断mid是否满足性质
		else l = mid + 1;
	}
	return l;
}


\———————————————————————————————— 整数二分模板1 ————————————————————————————————/

//模板2
/———————————————————————————————— 整数二分模板2 ————————————————————————————————\
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
public static int bsearch_2(int l, int r) {
	while (l < r) {
		int mid = l + r + 1 >> 1;
		if (check(mid)) l = mid;
		else r = mid - 1;
	}
	return l;
}
\———————————————————————————————— 整数二分模板2 ————————————————————————————————/

浮点二分模板

浮点数二分解析

在这里插入图片描述

用二分的思想可以找出这个分界点。
假设我们想二分出来红色(不满足条件的范围)这边的分界点

  1. 找一个中间值mid :(l+r) / 2(因为是浮点数,所以可以严格的二分,即mid就是中点)
  2. 写一个函数check()判断时mid时在满足条件(绿色)范围内,还是在不满足条件(红色)范围内。
  3. 当区间长度很小的时候,可以近似的认为找到了答案,例:r-l ≤ 10 − 6 ^{-6} 6 (如果题目要求保留4位小数,则应该写到-6次方,比有效小数的位数多2)

实验4

第1题

1、给定数组a[0 : 8]={1, 8, 12, 15, 16, 21, 30, 35, 39}。采用二分搜索算法完成下述任务:

  1. 查找是否有元素30,若有返回元素在数组中的位置;如没有返回无此元素。
  2. 查找是否有元素20,若有返回元素在数组中的位置;如没有返回无此元素。
  3. 当待搜索元素x=10不在数组中时,返回小于x的最大元素位置i和大于x的最小元素位置j。
public class binarySearch {
    static int a[] = new int[]{1, 8, 12, 15, 16, 21, 30, 35, 39};
    public static int binarySearch(int[] a, int x, int n) {
        int l = 0, r = n - 1;
        while (l <= r) {
            int mid = l + r >> 1;
            if (x == a[mid]) return mid;
            if (x > a[mid]) l = mid + 1;
            else r = mid - 1;
        }
        return -1;
    }

    public static int binarySearch3(int[] a, int x, int n) {
        int l = 0, r = n - 1;
        while (l <= r) {
            int mid = l + r >> 1;
            if (x == a[mid]) return mid;
            if (x > a[mid]) l = mid + 1;
            else r = mid - 1;
        }
        int i = l;
        int j = r;
        System.out.println("(3)" +'\n' +"a[]中没有10这个元素" + '\n' + "小于10的最大元素位置i为:" + i + '\n' + "大于10的最小元素位置j为:" + j);
        return -1;
    }

    public static void main(String[] args) {
        int l = 0, r = 8;
        int idx1 = binarySearch(a, 30, r + 1);
        int idx2 = binarySearch(a, 20, r + 1);
        if (idx1 == -1) System.out.println("(1) a[]中没有30这个元素");
        else System.out.println("(1) a[]中30这个元素在:" + idx1);

        if (idx2 == -1) System.out.println("(2) a[]中没有20这个元素");
        else System.out.println("(2) a[]中20这个元素在:" + idx2);

        binarySearch3(a, 10, r + 1);

    }
}

第2题

2、给定数组a[ ]={8,4,3,7,1,5,6,2},使用快速排序算法对其进行排序,将算法编程实现。

  1. 写出算法实现代码并截屏程序的运行结果。
  2. 分析快速排序算法在最好以及最坏情况下的时间复杂性。
  3. 快速排序算法的性能与划分是否对称有关,设计随机化的快速排序算法解决划分对称性问题,将算法编程实现。

快速排序:
1.分治 —— 先分出两边再递归

  1. 确定分界点,一般为三个点: q q q[l](左边界)、 q q q[l+r>>1](中间)或 q q q[r](右边界)(这里取中间为分界点👇)
  2. 假设分界点为x
    分为两个部分,保证第一个部分的位置 ≤ x ≤x x,第二个部分的位置 ≥ x ≥x x
  3. 递归处理左右两端
import java.util.*;
public class quickSort {
    static int a[] = new int []{8, 4, 3, 7, 1, 5, 6, 2};
//    /————————————————————快排模板————————————————————\
    public static void quick_sort(int a[], int l, int r) {
        if (l >= r) return;
        //取分界点x,可以取a[l]、a[r]或a[l+r>>1](+的优先级高于>>所以不用括号)
        // l+r>>1 比 (l+r)/2 的效率高
        int x = a[(l + r) >> 1];//取中间为分界点
        int i = l - 1, j = r + 1;//选择两个指针i,j,分别为两侧
        //每次移动一次交换算迭代
        while (i < j) {
            do i++; while (a[i] < x);//i指针往后移
            do j--; while (a[j] > x);//j指针往前移
            //i和j还没有相遇的话,i指向的数应该放到后面,j指向的数应该放到前面
            if (i < j) {
                int t = a[i];
                a[i] = a[j];
                a[j] = t;
            } else break;
        }

        //此时已经是左边的数都比x小,右边的数都比x大。
        quick_sort(a, l, j);
        quick_sort(a, j + 1, r);
        //当边界取q[l]时,这里的j不能用i-1来代替,j+1不能用i来代替,会进入死循环一直递归相同的区间
        //当边界取q[r]时,这里不能用j和j+1,会进入死循环一直递归相同的区间
    }
//    \————————————————————快排模板————————————————————/
    public static void main(String[] args) {
        System.out.println("排序前的结果是:" + Arrays.toString(a));
        quick_sort(a, 0, 7);
        System.out.println("排序后的结果是:" + Arrays.toString(a));
    }
}

快速排序的时间性能取决于快速排序递归的深度
最好的情况下时间复杂度:O(nlogn)。
假设树划分得很均匀,有n个待排序的数字,那么递归树的深度就为log2n+1
时间复杂度就是:O(nlogn)

T ( n ) = { O ( 1 ) , n = 1 2 T ( n 2 ) + O ( n ) , n > 1 T(n)=\left\{ \begin{aligned} O(1) &,n=1 \\ 2T(\frac{n}{2})+O(n)&,n>1 \end{aligned} \right. T(n)=O(1)2T(2n)+O(n),n=1,n>1

所以: T ( n ) = O ( n l o g n ) T(n) = O(nlog n) T(n)=O(nlogn)

假设树划分得很不均匀,就是一颗斜数(待排序的序列为正序或者逆序),此时需要执行n‐1次递归调用,此时时间复杂度就是:O(n2)

T ( n ) = { O ( 1 ) , n = 1 T ( n − 1 ) + O ( n ) , n > 1 T(n)=\left\{ \begin{aligned} O(1) &,n=1 \\ T(n-1)+O(n) &,n>1 \end{aligned} \right. T(n)={O(1)T(n1)+O(n),n=1,n>1

所以: T ( n ) = O ( n 2 ) T(n) = O(n^2) T(n)=O(n2)

import java.util.Arrays;
import java.util.Random;
public class randomQuickSort {
    private static int random(int p, int r) {
        Random random = new Random();
        int i =  random.nextInt(r - p + 1) + p;
        return i;
    }
    private static void quickSort(Comparable[] a, int p, int r) {
        if(p < r) {
            int q = randomizedPartition(a, p, r);
            quickSort(a, p, q - 1);
            quickSort(a, q + 1, r);
        }
    }
    private static int randomizedPartition(Comparable[] a, int p, int r) {
        int i = random(p, r);
        Comparable temp = a[i];
        a[i] = a[p];
        a[p] = temp;
        return partition(a, p, r);
    }
    private static int partition(Comparable[] a, int p, int r) {
        int i = p;
        int j = r + 1;
        Comparable x = a[p];
        while(true) {
            while(a[++i].compareTo(x) < 0 && i < r);
            while(a[--j].compareTo(x) > 0);
            if(i >= j) break;
            Comparable temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
        a[p] = a[j];
        a[j] = x;
        return j;
    }
    public static void main(String[] args) {
        Comparable[] a = {8, 4, 3, 7, 1, 5, 6, 2};
        System.out.println("排序前的数组:" + Arrays.toString(a));
        quickSort(a, 0, a.length - 1);
        System.out.println("排序后的数组:" + Arrays.toString(a));
    }
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值