《算法导论的Java实现》 9 线性时间排序

chen09 2011-05-31 12:57:43
Blog地址:
《算法导论的Java实现》 9 线性时间排序

9 线性时间排序

9.2 计数排序
伪代码:

COUNTING-SORT(A, B, k)
1 for i ← 0 to k
2 do C[i] ← 0
3 for j ← 1 to length[A]
4 do C[A[j]] ← C[A[j]] + 1
5 ▹ C[i] now contains the number of elements equal to i.
6 for i ← 1 to k
7 do C[i] ← C[i] + C[i - 1]
8 ▹ C[i] now contains the number of elements less than or equal to i.
9 for j ← length[A] downto 1
10 do B[C[A[j]]] ← A[j]
11 C[A[j]] ← C[A[j]] - 1



Java代码:

public class CountingSort {

public static int[] countingSort(int[] A, int k) {
int[] B = new int[A.length];
int[] C = new int[k];

for (int i = 0; i < k; i++)
C[i] = 0;
for (int i = 0; i < A.length; i++)
C[A[i]] += 1;
for (int i = 1; i < k; i++)
C[i] += C[i - 1];
for (int i = A.length - 1; i >= 0; i--) {
B[C[A[i]] - 1] = A[i];
C[A[i]] -= 1;
}
return B;
}

public static void main(String[] args) {
int[] A = { 2, 5, 3, 0, 2, 3, 0, 3 };
int[] B = countingSort(A, 6);
for (int b : B) {
System.out.print(b + " ");
}
System.out.println();
}

}



输出:
0 0 2 2 3 3 3 5

code后感
不同于“比较排序”(插入排序,堆排序,快速排序,都是要“比较”数组的值的,所以都是“比较排序”),计数排序的速度非常快,而且是个“稳定排序”。
程序本身非常干净,一共只是4个循环。
最后一个循环稍微有一点点难解,Java程序的数组下标的起始值和伪代码里面的不太相同。
《算法导论》第一版和第二版在这段伪代码里面的数组下标的起始值本身就不同。幸亏代码本身不难,所以也不会有太大困扰。
建议单步跟踪着来运行Java代码,观察A,B,C数组的值的变化,可以看出A,B,C数组的值和《算法导论》里面的图示是一致的。这样可以更容易的去理解这个算法。


9.3 基数排序
伪代码:
RADIX-SORT(A, d)
1 for i ← 1 to d
2 do use a stable sort to sort array A on digit i


Java代码:


public class RadixSort {

private static int[] countingSort(int[] A, int d) {
int[] B = new int[A.length];
int[] C = new int[10];
for (int i = 0; i < 10; i++)
C[i] = 0;
for (int i = 0; i < A.length; i++)
C[A[i] % ((int) Math.pow(10, d + 1)) / ((int) Math.pow(10, d))] += 1;
for (int i = 1; i < 10; i++)
C[i] += C[i - 1];
for (int i = A.length - 1; i >= 0; i--) {
B[C[A[i] % ((int) Math.pow(10, d + 1)) / ((int) Math.pow(10, d))] - 1] = A[i];
C[A[i] % ((int) Math.pow(10, d + 1)) / ((int) Math.pow(10, d))] -= 1;
}
return B;
}

public static int[] radixSort(int[] A, int d) {
int[] B = new int[A.length];
for (int i = 0; i < A.length; i++)
B[i] = A[i];
for (int i = 0; i < d; i++) {
B = countingSort(B, i);
}
return B;
}

public static void main(String[] args) {
int[] A = { 12, 25, 13, 30, 32, 43, 20, 3 };
int[] B = radixSort(A, 2);
for (int b : B) {
System.out.print(b + " ");
}
System.out.println();

}

}



输出:
3 12 13 20 25 30 32 43

code后感
伪代码很短,Java代码有点长。
因为第二行伪代码是说:以数组A的第i位为键,用一个稳定排序来排。
迄今为止,《算法导论》里介绍过的稳定排序,只有前一节的计数排序,而那一节的计数排序,显然不能直接用在这里。不得不把前一节的计数排序改写一下。
必须注意的是,这一节的计数排序public static int[] countingSort(int[] A, int d)和前一节的参数(int[] A, int d)虽然相同,但是意义完全不同。前一节的计数排序里,第二参数(int k),是表示数组A可能的值的个数。上一节里的例子,数组A在0到5之间,所以k为6。这一节,考虑排列的是10进制数,所以就在程序里定下为10,不由参数引入,而
(int d)是排序的键值所在的位数,测试程序里,d会做循环,从0到1为止。


9.4 桶排序
伪代码:

BUCKET-SORT(A)
1 n ← length[A]
2 for i ← 1 to n
3 do insert A[i] into list B[⌊n A[i]⌋]
4 for i ← 0 to n - 1
5 do sort list B[i] with insertion sort
6 concatenate the lists B[0], B[1], . . ., B[n - 1] together in order



Java代码:


import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;

public class BucketSort {
public static <T> void insertionSort(T[] t, Comparator<? super T> comparator) {
for (int j = 1; j < t.length; j++) {
T key = t[j];
int i = j - 1;
while (i > -1 && comparator.compare(t[i], key) > 0) {
t[i + 1] = t[i];
i--;
}
t[i + 1] = key;
}
}

public static Double[] bucketSort(Double[] A) {
List<Double>[] B = new List[10];

for (int i = 0; i < B.length; i++)
B[i] = new LinkedList<Double>();
for (Double d : A)
B[(int) (d * 10)].add(d);

Double[][] BB = new Double[10][];
List<Double> BBB = new LinkedList<Double>();
for (int i = 0; i < B.length; i++) {
BB[i] = B[i].toArray(new Double[0]);
insertionSort(BB[i], new Comparator<Double>() {
public int compare(Double o1, Double o2) {
return (int) (Math.signum(o1 - o2));
}
});
for (Double d : BB[i])
BBB.add(d);
}
return BBB.toArray(new Double[0]);
}

public static void main(String[] args) {
Double[] doubles = new Double[] { 0.78, 0.17, 0.39, 0.26, 0.72, 0.94,
0.21, 0.12, 0.23, 0.68 };
doubles = bucketSort(doubles);
for (Double d : doubles)
System.out.print(d + " ");
System.out.println();
}

}


输出:
0.12 0.17 0.21 0.23 0.26 0.39 0.68 0.72 0.78 0.94

code后感
和上一节一样,伪代码短,Java代码很长。
原因在于,桶排序的第一步是将各个待排元素装到桶里,第二步就是对各个桶进行插入排序。
插入排序insertionSort,在1.1.1节我已经介绍过,在这里,把1.1.1的程序原封不动,copy过来使用。让忘记插入排序的人,再复习一下。

第9章《线性时间排序》就这么结束了,程序都比较简单,相比堆排序和快速排序,无论计数排序还是基数排序,亦或桶排序,理解伪代码并不困难。但是,都用到了前面的知识,所以温故而知新,复习一下前面的插入排序还是有必要的。

总体来说,插入排序等是最慢的,考虑到一般性,堆排序和快速排序都是不错的选择。
如果只是整数,那看情形使用计数或者基数排序,如果是浮点数,那么可以选择桶排序。

...全文
311 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
chen09 2011-06-07
  • 打赏
  • 举报
回复
顶到出新篇
xiaomowen_74839 2011-06-02
  • 打赏
  • 举报
回复
顶到出新篇
xiaomowen_74839 2011-06-02
  • 打赏
  • 举报
回复
顶到出新篇
xiaomowen_74839 2011-06-02
  • 打赏
  • 举报
回复
好东西,顶一个。
chen09 2011-06-02
  • 打赏
  • 举报
回复
顶到出新篇
chen09 2011-06-02
  • 打赏
  • 举报
回复
顶到出新篇
皮特张 2011-06-01
  • 打赏
  • 举报
回复
顶到出新篇
chen09 2011-06-01
  • 打赏
  • 举报
回复
顶到出新篇
chen09 2011-06-01
  • 打赏
  • 举报
回复
顶到出新篇
TKD03072010 2011-05-31
  • 打赏
  • 举报
回复
不错呀!楼主辛苦了!学习!
baobao28 2011-05-31
  • 打赏
  • 举报
回复
很好,收藏了
皮特张 2011-05-31
  • 打赏
  • 举报
回复
好帖子,
皮特张 2011-05-31
  • 打赏
  • 举报
回复
人工置顶。呵呵
一、本书的内容 目前,市面上有关计算机算法的书很多,有些叙述严谨但不全面,另外一些则是容量很大但不够严谨。本书将叙述的严谨性以及内容的深度和广度有机地结合了起来。第1版推出后,即在世界范围内受到了广泛的欢迎,被各高等院校用作多种课程的教材和业界的标准参考资料。它深入浅出地介绍了大量的算法及相关的数据结构,以及用于解决一些复杂计算问题的高级策略(如动态规划、贪心算法、平摊分析等),重点在于算法的分析和设计。对于每一个专题,作者都试图提供目前最新的研究成果及样例解答,并通过清晰的图示来说明算法的执行过程。. 本书是原书的第2版,在第1版的基础之上增加了一些新的内容,涉及算法的作用、概率分析和随机化算法、线性规划,以及对第1版中详尽的、几乎涉及到每一小节的修订。这些修订看似细微,实际上非常重要。书中引入了“循环不变式”,并贯穿始终地用来证明算法的正确性。在不改动数学和分析重点的前提下,作者将第1版中的许多数学基础知识从第一部分移到了附录中。 二、本书的特点 本书在进行算法分析的过程中,保持了很好的数学严谨性。书中的分析和设计可以被具有各种水平的读者所理解。相对来说,每一章都可以作为一个相对独立的单元来教授或学习。书中的算法以英语加伪代码的形式给出,只要有一点程序设计经验的人都能读懂,并可以用任何计算机语言(如C/C++和Java等)方便地实现。在书中,作者将算法的讨论集中在一些比较现代的例子上,它们来自分子生物学(如人类基因项目)、商业和工程等领域。每一小节通常以对相关历史素材的讨论结束,讨论了在每一算法领域的原创研究。 本书的特点可以概括为以下几个方面: 1.概念清晰,广度、深度兼顾。 本书收集了现代计算机常用的数据结构和算法,并作了系统而深入的介绍。对涉及的概念和背景知识都作了清晰的阐述,有关的定理给出了完整的证明。 2.“五个一”的描述方法。 本书以相当的深度介绍了许多常用的数据结构和有效的算法。编写上采用了“五个一”,即一章介绍一个算法、一种设计技术、一个应用领域和一个相关话题。.. 3.图文并茂,可读性强。 书中的算法均以通俗易懂的语言进行说明,并采用了大量插图来说明算法是如何工作的,易于理解。 4.算法的“伪代码”形式简明实用。 书中的算法均以非常简明的“伪代码”形式来设计,可以很容易地把它转化为计算机程序,直接应用。 注重算法设计的效率,对所有的算法进行了仔细、精确的运行时间分析,有利于进一步改进算法。 三、本书的用法 本书对内容进行了精心的设计和安排,尽可能考虑到所有水平的读者。即使是初学计算机算法的人,也可以在本书中找到所需的材料。 每一章都是独立的,读者只需将注意力集中到最感兴趣的章节阅读。 1.适合作为教材或教学参考书。 本书兼顾通用性与系统性,覆盖了许多方面的内容。本书不但阐述通俗、严谨,而且提供了大量练习和思考题。针对每一节的内容,都给出了数量和难度不等的练习题。练习题用于考察对基本内容的掌握程度,思考题有一定的难度,需进行精心的研究,有时还通过思考题介绍一些新的知识。 前言回到顶部↑本书提供了对当代计算机算法研究的一个全面、综合性的介绍。书中给出了多个算法,并对它们进行了较为深入的分析,使得这些算法的设计和分析易于被各个层次的读者所理解。力求在不牺牲分析的深度和数学严密性的前提下,给出深入浅出的说明。. 书中每一章都给出了一个算法、一种算法设计技术、一个应用领域或一个相关的主题。算法是用英语和一种“伪代码”来描述的,任何有一点程序设计经验的人都能看得懂。书中给出了230多幅图,说明各个算法的工作过程。我们强调将算法的效率作为一种设计标准,对书中的所有算法,都给出了关于其运行时间的详细分析。 本书主要供本科生和研究生的算法或数据结构课程使用。因为书中讨论了算法设计中的工程问题及其数学性质,因此,本书也可以供专业技术人员自学之用。 本书是第2版。在这个版本里,我们对全书进行了更新。所做的改动从新增了若干章,到个别语句的改写。 致使用本书的教师 本书的设计目标是全面、适用于多种用途。它可用于若干课程,从本科生的数据结构课程到研究生的算法课程。由于书中给出的内容比较多,只讲一学期一般讲不完,因此,教师们应该将本书看成是一种“缓存区”或“瑞典式自助餐”,从中挑选出能最好地支持自己希望教授的课程的内容。 教师们会发现,要围绕自己所需的各个章节来组织课程是比较容易的。书中的各章都是相对独立的,因此,你不必担心意想不到的或不必要的各章之间的依赖关系。每一章都是以节为单位,内容由易到难。如果将本书用于本科生的课程,可以选用每一章的前面几节内容;在研究生课程中,则可以完整地讲授每一章。 全书包含920多个练习题和140多个思考题。每一节结束时给出练习题,每一章结束时给出一些
一、本书的内容 目前,市面上有关计算机算法的书很多,有些叙述严谨但不全面,另外一些则是容量很大但不够严谨。本书将叙述的严谨性以及内容的深度和广度有机地结合了起来。第1版推出后,即在世界范围内受到了广泛的欢迎,被各高等院校用作多种课程的教材和业界的标准参考资料。它深入浅出地介绍了大量的算法及相关的数据结构,以及用于解决一些复杂计算问题的高级策略(如动态规划、贪心算法、平摊分析等),重点在于算法的分析和设计。对于每一个专题,作者都试图提供目前最新的研究成果及样例解答,并通过清晰的图示来说明算法的执行过程。. 本书是原书的第2版,在第1版的基础之上增加了一些新的内容,涉及算法的作用、概率分析和随机化算法、线性规划,以及对第1版中详尽的、几乎涉及到每一小节的修订。这些修订看似细微,实际上非常重要。书中引入了“循环不变式”,并贯穿始终地用来证明算法的正确性。在不改动数学和分析重点的前提下,作者将第1版中的许多数学基础知识从第一部分移到了附录中。 二、本书的特点 本书在进行算法分析的过程中,保持了很好的数学严谨性。书中的分析和设计可以被具有各种水平的读者所理解。相对来说,每一章都可以作为一个相对独立的单元来教授或学习。书中的算法以英语加伪代码的形式给出,只要有一点程序设计经验的人都能读懂,并可以用任何计算机语言(如C/C++和Java等)方便地实现。在书中,作者将算法的讨论集中在一些比较现代的例子上,它们来自分子生物学(如人类基因项目)、商业和工程等领域。每一小节通常以对相关历史素材的讨论结束,讨论了在每一算法领域的原创研究。 本书的特点可以概括为以下几个方面: 1.概念清晰,广度、深度兼顾。 本书收集了现代计算机常用的数据结构和算法,并作了系统而深入的介绍。对涉及的概念和背景知识都作了清晰的阐述,有关的定理给出了完整的证明。 2.“五个一”的描述方法。 本书以相当的深度介绍了许多常用的数据结构和有效的算法。编写上采用了“五个一”,即一章介绍一个算法、一种设计技术、一个应用领域和一个相关话题。.. 3.图文并茂,可读性强。 书中的算法均以通俗易懂的语言进行说明,并采用了大量插图来说明算法是如何工作的,易于理解。 4.算法的“伪代码”形式简明实用。 书中的算法均以非常简明的“伪代码”形式来设计,可以很容易地把它转化为计算机程序,直接应用。 注重算法设计的效率,对所有的算法进行了仔细、精确的运行时间分析,有利于进一步改进算法。 三、本书的用法 本书对内容进行了精心的设计和安排,尽可能考虑到所有水平的读者。即使是初学计算机算法的人,也可以在本书中找到所需的材料。 每一章都是独立的,读者只需将注意力集中到最感兴趣的章节阅读。 1.适合作为教材或教学参考书。 本书兼顾通用性与系统性,覆盖了许多方面的内容。本书不但阐述通俗、严谨,而且提供了大量练习和思考题。针对每一节的内容,都给出了数量和难度不等的练习题。练习题用于考察对基本内容的掌握程度,思考题有一定的难度,需进行精心的研究,有时还通过思考题介绍一些新的知识。 前言回到顶部↑本书提供了对当代计算机算法研究的一个全面、综合性的介绍。书中给出了多个算法,并对它们进行了较为深入的分析,使得这些算法的设计和分析易于被各个层次的读者所理解。力求在不牺牲分析的深度和数学严密性的前提下,给出深入浅出的说明。. 书中每一章都给出了一个算法、一种算法设计技术、一个应用领域或一个相关的主题。算法是用英语和一种“伪代码”来描述的,任何有一点程序设计经验的人都能看得懂。书中给出了230多幅图,说明各个算法的工作过程。我们强调将算法的效率作为一种设计标准,对书中的所有算法,都给出了关于其运行时间的详细分析。 本书主要供本科生和研究生的算法或数据结构课程使用。因为书中讨论了算法设计中的工程问题及其数学性质,因此,本书也可以供专业技术人员自学之用。 本书是第2版。在这个版本里,我们对全书进行了更新。所做的改动从新增了若干章,到个别语句的改写。 致使用本书的教师 本书的设计目标是全面、适用于多种用途。它可用于若干课程,从本科生的数据结构课程到研究生的算法课程。由于书中给出的内容比较多,只讲一学期一般讲不完,因此,教师们应该将本书看成是一种“缓存区”或“瑞典式自助餐”,从中挑选出能最好地支持自己希望教授的课程的内容。 教师们会发现,要围绕自己所需的各个章节来组织课程是比较容易的。书中的各章都是相对独立的,因此,你不必担心意想不到的或不必要的各章之间的依赖关系。每一章都是以节为单位,内容由易到难。如果将本书用于本科生的课程,可以选用每一章的前面几节内容;在研究生课程中,则可以完整地讲授每一章。 全书包含920多个练习题和140多个思考题。每一节结束时给出练习题,每一章结束时给出一些

62,612

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧