`
bencode
  • 浏览: 109634 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

《算法导论》读书笔记6(中位数和顺序统计学)

阅读更多

这一章《中位数和顺序统计学》很短,也是本书第二部分的最后一章

 

写几段代码吧。

 

求数组最小值

 

	int minimum(int[] a) {
		int min = a[0];
		for (int i = 1; i < a.length; i++) {
			if (min > a[i]) {
				min = a[i];
			}
		}
		return min;
	}

 

这个不用写测试,就当没写过。 这个方法需要做 n-1 次比较

 

同时找出最大值,最小值

 

如果用上面的方法,那么这个问题使用 2(n-1) 次比较肯定能解决。 当然可以更少一些。

 

	int[] minAndMax(int[] a) {
		int i = 1;
		int min = a[0];
		int max = a[0];
		
		if ((a.length & 1) == 0) { // 偶数
			i = 2;
			max = a[1];
		}
		
		if (min > max) {
			// swap
			int t = min;
			min = max;
			max = t;
		}
		// 下面从 i 开始,直到结束,共有偶数个数, 每次处理两个
		for (; i < a.length; i += 2) {
			int m = a[i];
			int n = a[i + 1];
			if (m > n) {
				// swap
				int t = m;
				m = n;
				n = t;
			}
			// now m <= n
			
			if (min > m) {
				min = m;
			}
			if (max < n) {
				max = n;
			}
		}
		
		int[] b = { min, max };
		return b;
	}

 

现在 每次循环 进行3 次比较, 共进行 3((n - 1) / 2) 次比较, 加上循环前的一次比较,共进行 3(n / 2) 次比较

 

选择第 i 小的数

 

我们可以进行一次排序,然后再输出第 i 小的数, 但这样复杂度会和排序一样

 

可以有更好的方法:

 

	int randSelect(int[] ary, int left, int right, int index) { // 从[left, right] 中找出第 index 小的数
		if (left > right || index > right - left) {
			throw new IllegalArgumentException();
		}
		
		if (left == right) {
			return ary[left]; // 此时 index == 0
		}

		int mid = partition(ary, left, right);  // 对数组进行一次划分,[left, mid - 1] [mid] [mid + 1, right]
		int len = mid - left;
		if (index == len) {  // 刚好
			return ary[mid];
		} else if (index < len) {  // 要找的数在左区间
			return randSelect(ary, left, mid - 1, index);
		} else {  // 要找的数在右区间, 当然此时要找第 index - len - 1小的数,因为要扣除左区间以及mid
			return randSelect(ary, mid + 1, right, index - len - 1);
		}
	}

 

其中 partition 在快速排序中遇到过

 

	int partition(int[] a, int low, int high) {
		int x = a[low];
		int m = low;
		for (int i = low + 1; i <= high; i++) {
			if (a[i] < x) {
				swap(a, ++m, i);
			}
		}
		swap(a, low, m);
		
		return m;
	}
	
	void swap(int[] a, int i, int j) {
		int t = a[i];
		a[i] = a[j];
		a[j] = t;
	}

 

不忙, 写个测试先。

 

	@Test
	public void testRandSelect() {
		Random rand = new Random();
		
		for (int i = 0; i < 100; i++) {
			int[] a = genRandAry(i + 1);
			int[] b = Arrays.copyOf(a, a.length); // 因为 randSelect会对数组a进行重排,所以先copy一份
			
			int k = rand.nextInt(a.length);  // 我们要从a中选出第 k 小的数
			int m = randSelect(a, 0, a.length - 1, k); 
			Arrays.sort(b); // 再对b进行排序
			assertEquals(b[k], m);  // 此时 m 就应该和 b[k] 一样
		}
	}

 

可以看到,运行是通过的:)

 

下面我们看分析其复杂度。

 

 首先重构 randSelect 将其修改为求比较次数

 

 

	int randSelect2(int[] ary, int left, int right, int index) {
		if (left > right || index > right - left) {
			throw new IllegalArgumentException();
		}
		
		if (left == right) {
			return 0; // modified
			//return ary[left];
		}

		int times = right - left; // 下面的partition要作 right - left 次比较, 见快速排序(笔记4)
		int mid = partition(ary, left, right);
		int len = mid - left;
		if (index == len) {
			return times;
			//return ary[mid];
		} else if (index < len) {
			return times + randSelect(ary, left, mid - 1, index); // modified
		} else {
			return times + randSelect(ary, mid + 1, right, index - len - 1); // modified
		}
	}

 

然后对上面的方法进行简化

1.  参数检查不需要

2. left == right 测试 ---> n == 0

3. 把left 和 right 等表示成 n 相关, 并去掉 a, index

3. 在一般情况下,partition 分得很平均, 并且我们假设代码路径都只经过 index < len 这个分支

 

上面的方法即可简化成求平均比较次数

 

	int randSelect2(int n) {
		if (n == 0) {
			return 0;
		}
		int times = n - 1;	// partition比较次数
		return times + randSelect2(n / 2); // 每次分割后n 减半
	}

 

写成递归式就是 T(n) = T(n / 2) + (n - 1) 

 

上面这个写成数列就是: (n - 1) + (n - 1) / 2 + (n - 1) / 4 + (n - 1) / 8 + ...

 

即 (n - 1)( 1 + 1/2 + 1/4 + 1/8 + ..) ---> 差不多的 2(n-1) 

 

所以randSelect算法复杂度是线性的 

 

当然也可以使用算法笔记2中的工具进行绘制, 看其复杂度

 



 

和2(n-1)相符!

 

  • 大小: 5.5 KB
分享到:
评论

相关推荐

    算法导论系列读书笔记之二

    作为“算法导论系列读书笔记之二”,本文将主要探讨第二章的内容,这一章通常涵盖基础的数据结构和算法,为后续章节的学习打下坚实的基础。 在算法分析中,"循环不变式"是一个至关重要的概念。它是指在循环开始前、...

    算法导论 读书笔记

    在本读书笔记中,涉及到的算法知识点主要包含在《算法导论》的附录A习题解答中,内容涵盖等差级数求和、调和级数性质、无穷递减几何级数、求和的渐近上界及下界、积分求近似值以及思考题中求和的界等问题。...

    算法导论系列读书笔记之六

    《算法导论》系列读书笔记之六主要涵盖了优先级队列、堆排序以及大根堆和最大堆等重要概念。这些知识点在计算机科学与技术领域,尤其是数据结构和算法分析中占据着核心地位。下面将对这些内容进行深入的探讨。 ...

    算法导论读书笔记(整理别人的)

    《算法导论》是计算机科学领域的一本经典著作,它深入浅出地介绍了各种重要的算法,并提供了详尽的分析和实现。这篇读书笔记主要涵盖了以下几个方面的重要知识点: 1. **算法基础**:算法是解决问题的步骤序列,是...

    读书笔记:算法导论 练习笔记.zip

    读书笔记:算法导论 练习笔记

    算法导论 学习笔记.pdf

    算法导论学习笔记 本资源是对《算法导论》的学习笔记,涵盖了算法的基础知识、算法分析、函数的增长、递归式等方面的内容。 一、算法基础知识 算法是指将输入转换为输出的一系列计算步骤,目的是为了有效利用...

    算法导论 第三版 中文pdf

    算法导论 第三版 中文pdf

    算法导论英文笔记和答案(较全)

    在“中位数和顺序统计”章节中,文档探讨了如何高效地计算数据集中的中位数和其他顺序统计量,这对于统计分析和排序算法性能的优化非常重要。 “哈希表”章节讲解了哈希表数据结构的原理及其在数据存储和检索中的...

    麻省理工算法导论及笔记

    《算法导论》中还涉及了计算复杂性和NP完全理论,这些理论帮助我们理解哪些问题是可以在有限时间内解决的,哪些可能是无法解决的。此外,书中还包括概率算法和随机化技术,例如鸽巢原理、大数定律以及Monte Carlo和...

    MIT 算法导论 课堂笔记

    《MIT算法导论》是计算机科学领域的一部经典教材,由Thomas H. Cormen、Charles E. Leiserson、Ronald L. Rivest和Clifford Stein...同时,Word文档的格式使得笔记易于阅读和整理,方便你在学习过程中随时查阅和复习。

    算法导论系列读书笔记之附录A的习题解答

    这篇读书笔记将针对附录A中的习题进行解析,帮助读者深化对算法的理解。 首先,附录A的习题涵盖了许多基础概念和理论,例如排序、搜索、图算法、动态规划等。在排序方面,可能会涉及冒泡排序、插入排序、选择排序、...

    算法导论中文第三版习题答案

    《算法导论》是计算机科学领域的一本经典著作,它深入浅出地介绍了算法的设计、分析和实现。中文第三版的出版,使得更多的中文读者能够接触到这本权威教材。本书覆盖了从排序和搜索到图算法,再到动态规划和贪心算法...

    算法导论第三版完整版答案

    《算法导论》是计算机科学领域的一本经典著作,它深入浅出地介绍了算法的设计、分析和实现。这本书的第三版更是对前两版进行了完善和更新,涵盖了更广泛的主题和最新的研究成果。针对你提到的“算法导论第三版完整版...

    算法导论 中英文高清版本

    《算法导论》是一本备受推崇的计算机科学教材,它深入浅出地介绍了算法的设计、分析和实现。这本书由Thomas H. Cormen、Charles E. Leiserson、Ronald L. Rivest和Clifford Stein四位作者共同撰写,是全球范围内...

    算法导论中文版

    针对编程新手而言,阅读《算法导论中文版》并实践书中的算法不仅可以帮助他们建立起对算法的基本理解,还能提升解决实际问题的能力。通过学习算法,新手可以加深对程序设计的洞察,提高编程逻辑思维,为今后成为更...

    算法导论的笔记与答案

    ##### 2.8 第九章:中位数与顺序统计量 - **讲座笔记**:讨论了如何找到一个数组中的第k小元素,特别是如何有效地找出中位数。 - **解决方案**:提供了几种不同的算法来解决这个问题,并分析了它们的优缺点。 #####...

    算法导论答案算法导论教师手册

    《算法导论教师手册》为教师提供了丰富的教学资源,包括详尽的讲座笔记、习题解答和案例分析,有助于教师更好地理解和传授算法知识,同时也能帮助学生深入学习,巩固理论知识,提高解决实际问题的能力。 总之,...

    算法导论第四版 英文

    《算法导论第四版》是普林斯顿大学计算机科学系教授Robert Sedgewick和Kevin Wayne所编写的一部经典算法教材。该书深入浅出地介绍了计算机算法设计与分析的各个方面,涵盖了从基本的数据结构到复杂算法的理论知识和...

    算法导论试题及答案

    Rivest和Clifford Stein四位作者共同编写,广泛应用于全球各大高校的教学中,包括知名的麻省理工学院(MIT)。这本书深入浅出地介绍了算法设计和分析的基本方法,涵盖了排序、搜索、图算法、动态规划等诸多主题,是...

Global site tag (gtag.js) - Google Analytics