数据结构与算法拾遗一

本文探讨了数据结构在数组和跳转结构中的应用,展示了如何通过预处理提高求范围和的效率。此外,文章还介绍了如何实现1-5到1-7的等概率随机数转换,以及如何从不等概率随机数生成等概率随机数。同时,通过比较选择排序和插入排序,验证了排序算法的正确性。
摘要由CSDN通过智能技术生成

数据结构:连续结构加跳转结构租车
1、数据结构是存储、组织数据的方式
2、精心选择的数据结构可以带来更高的运行或者存储效率
3、数据结构是很多算法得以进行的载体

数组结构: 寻址容易,增删数据难 跳转结构: 寻址难,增删数据容易

求数组L到R的和

public static class RangeSum1 {

		private int[] arr;

		public RangeSum1(int[] array) {
			arr = array;
		}

		public int rangeSum(int L, int R) {
			int sum = 0;
			for (int i = L; i <= R; i++) {
				sum += arr[i];
			}
			return sum;
		}

	}

	public static class RangeSum2 {

		private int[] preSum;

		public RangeSum2(int[] array) {
			int N = array.length;
			preSum = new int[N];
			preSum[0] = array[0];
			for (int i = 1; i < N; i++) {
				preSum[i] = preSum[i - 1] + array[i];
			}
		}

		public int rangeSum(int L, int R) {
			return L == 0 ? preSum[R] : preSum[R] - preSum[L - 1];
		}

	}

Math.random()随机数 ([0,1)左闭右开区间且等概率返回值)

public static void main(String[] args) {
		System.out.println("测试开始");
		// Math.random() -> double -> [0,1)
		//

		int testTimes = 10000000;
		int count = 0;
		for (int i = 0; i < testTimes; i++) {
			if (Math.random() < 0.75) {
				count++;
			}
		}
		System.out.println((double) count / (double) testTimes);

		System.out.println("=========");

		// [0,1) -> [0,8)
		count = 0;
		for (int i = 0; i < testTimes; i++) {
			if (Math.random() * 8 < 5) {
				count++;
			}
		}
		System.out.println((double) count / (double) testTimes);
		System.out.println((double) 5 / (double) 8);

		int K = 9;
		// [0,K) -> [0,8] 转为整形则范围为0-K-1的左闭右闭的区间

		int[] counts = new int[9];
		for (int i = 0; i < testTimes; i++) {
			int ans = (int) (Math.random() * K); // [0,K-1]
			counts[ans]++;//计算当前范围内的各个数出现的次数
		}
		for (int i = 0; i < K; i++) {
			System.out.println(i + "这个数,出现了 " + counts[i] + " 次");
		}

		System.out.println("=========");

		//返回概率调整为x的方
		count = 0;
		double x = 0.7;
		for (int i = 0; i < testTimes; i++) {
			if (xToXPower2() < x) {
				count++;
			}
		}
		System.out.println((double) count / (double) testTimes);
		System.out.println((double) 1 - Math.pow((double) 1 - x, 2));
		}
		

	// 返回[0,1)的一个小数
	// 任意的x,x属于[0,1),[0,x)范围上的数出现概率由原来的x调整成x平方
	public static double xToXPower2() {
		//只有两次行为全部成立才会落在[0,x)上面
		//return Math.max(Math.random(), Math.random());
		//此方式的概率为1-(1-x)*(1-x)
		return Math.min(Math.random(),Math.random());
	}

写一个函数从1-5随机到1-7随机(不能用Math.random):

将1-5的函数改成一个0-1的等概率发生器
1-2 返回0
4-5返回1
得到3则重新来一遍

public static int f1() {
		return (int) (Math.random() * 5) + 1;
	}

	// 随机机制,只能用f1,
	// 等概率返回0和1
	public static int f2() {
		int ans = 0;
		do {
			ans = f1();
		} while (ans == 3);
		// 1,2->0 4,5 ->1
		return ans < 3 ? 0 : 1;
	}

测试代码如下:

	count = 0;
		for (int i = 0; i < testTimes; i++) {
			if (f2() == 0) {
				count++;
			}
		}
		System.out.println((double) count / (double) testTimes);

如何得到0-7范围的数呢?

	// 得到二进制位000 ~ 111 做到等概率 0 ~ 7等概率返回一个
	public static int f3() {
		return (f2() << 2) + (f2() << 1) + f2();
	}

再通过0-7得到0-6的等概率返回

	// 0 ~ 6等概率返回一个
	public static int f4() {
		int ans = 0;
		do {
			ans = f3();
		} while (ans == 7);
		return ans;
	}

1-7等概率返回为如下调用

	public static int g() {
		return f4() + 1;
	}

测试代码如下:

	counts = new int[8];
		for (int i = 0; i < testTimes; i++) {
			int num = g();
			counts[num]++;
		}
		for (int i = 0; i < 8; i++) {
			System.out.println(i + "这个数,出现了 " + counts[i] + " 次");
		}

0-1不等概率随机到0-1等概率随机(不能引入任何随机)

首先 0的概率是 p 然后1的概率为1-p
我们将它row两次 得到 0 0(概率为pp) 的不要,得到 1 1(概率为(1-p)(1-p))的不要
得到 0 1 和1 0 的概率都为 p*(1-p)
代码如下:

// 你只能知道,x会以固定概率返回0和1,但是x的内容,你看不到!
	public static int x() {
		return Math.random() < 0.84 ? 0 : 1;
	}

	// 等概率返回0和1
	public static int y() {
		int ans = 0;
		do {
			ans = x();
		} while (ans == x());
		return ans;
	}

对数器使用

这里以验证选择排序和插入排序为例子

public static void selectionSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		for (int i = 0; i < arr.length - 1; i++) {
			int minIndex = i;
			for (int j = i + 1; j < arr.length; j++) {
				if (arr[j] < arr[minIndex]) {
					minIndex = j;
				}
			}
			swap(arr, i, minIndex);
		}
	}

	public static void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}

	public static void insertionSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		for (int i = 1; i < arr.length; i++) { // 0 ~ i 做到有序
			for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
				swap(arr, j, j + 1);
			}
		}
	}

	// 返回一个数组arr,arr长度[0,maxLen-1],arr中的每个值[0,maxValue-1]
	public static int[] lenRandomValueRandom(int maxLen, int maxValue) {
		int len = (int) (Math.random() * maxLen);
		int[] ans = new int[len];
		for (int i = 0; i < len; i++) {
			ans[i] = (int) (Math.random() * maxValue);
		}
		return ans;
	}

	public static int[] copyArray(int[] arr) {
		int[] ans = new int[arr.length];
		for (int i = 0; i < arr.length; i++) {
			ans[i] = arr[i];
		}
		return ans;
	}

	// arr1和arr2一定等长
	public static boolean isSorted(int[] arr) {
		if (arr.length < 2) {
			return true;
		}
		int max = arr[0];
		for (int i = 1; i < arr.length; i++) {
			if (max > arr[i]) {
				return false;
			}
			max = Math.max(max, arr[i]);
		}
		return true;
	}

	public static void main(String[] args) {
		int maxLen = 5;
		int maxValue = 1000;
		int testTime = 10000;
		for (int i = 0; i < testTime; i++) {
			int[] arr1 = lenRandomValueRandom(maxLen, maxValue);
			int[] tmp = copyArray(arr1);
			selectionSort(arr1);
			if (!isSorted(arr1)) {
				for (int j = 0; j < tmp.length; j++) {
					System.out.print(tmp[j] + " ");
				}
				System.out.println();
				System.out.println("选择排序错了!");
				break;
			}
		}

	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值