Java数据结构和算法-简单排序(1-冒泡排序)

来源:互联网 发布:沪宁杭 知乎 编辑:程序博客网 时间:2024/06/04 18:05

一般在创建数据库之后,就可能对某些数据进行排序。例如:对商店的销售品按价格排序,对城市按人口增长率进行排序等。排序一般作为检索的一个初始步骤,正如在前面所讲的数组中,二分查找要比线性查找快的多,但是二分查找只适用于有序的数据。
排序非常重要但又十分耗时,因此它成为了一个计算机科学领域广泛研究的课题,并且也已经有了不少的成就。比如在本章的简单排序中的冒泡排序、选择排序和插入排序。
本章描述的算法很简单,执行速度也比较慢,但任然是值得学习的。因为在有些情况,这些算法比那些复杂的算法更好一些,比如小范围的数据或者基本有序的数据时,插入排序比快速排序更加有效。并且实际上,插入排序也作为了快速排序实现的一部分。
在实际生活中,对一群人由低到高进行排列,人们可以一眼找出最高的那个,但是对于计算机,却只能通过不断的进行两两比较来得出答案,人们能够全览所有的数据,但计算机却不能看到全景,因此它只能一步一步地解决具体的问题和遵循一些基础的规则。比如在本章要学习的三个排序算法,计算机都要执行下面两个步骤,不断重复执行,直到全部数据有序为止:

  1. 比较两个数据项;
  2. 交换两个数据项,或者复制其中一项;

不同的算法这两个规则可能有少许的不同,但大致是这样的。

1.冒泡排序

冒泡排序算法运行起来非常的慢,但是它是所有排序算法当中最为简单的。

现实的列子

在我们上体育课的时候,老师都会让体育委员对所有学生进行由低到高的排列。如果将体育委员视为计算机,那么它将无法看到全景,只能通过两两比较来进行排序。假设要排序的学生总数为N,将其位置由0到N-1进行编号。
冒泡排序程序执行如下:从队列的最左边开始,先比较在编号0和编号1位置的学生,如果左边的0号位置比右边的1号位置的学生高,则交换两者的位置,否则什么也不做。接着右移一个位置,比较1号位置和2号位置的学生。和刚才一样,如果左边的学生比右边的高,则交换两者的位置,否则什么也不做。由此重复以下规则:
1.比较两个学生;
2.若左边的学生高于右边,则将两者进行交换;
3. 向右移动一个位置,比较下面两个学生;
沿着这个队伍不断的比较下去,直到队伍的最右端,此时最高的学生已经排在了最右端,虽然左边的任然是无序的。这也是这个排序算法为什么叫冒泡算法的原因:因为在算法执行时,最大的数据总会冒泡到最右端。
在对所有的学生进行第一趟排序之后,总共进行了N-1次的比较,并且按照学生的初始位置,至少进行了0次位置的交换,最多N-1次交换。数组最末端的学生就此排定不再改变。
然后接着回到队伍的最左端重复上述步骤,两两比较,并且在适当的时候交换两个学生之间的位置。不过右端已经排定的学生已经不再变化,所以第二趟只需进行N-2次比较。
这总规则可以描述为:当碰到排定的第一个学生时,就回到队伍的最左端,重新开始下一趟排序。
不断执行上述过程直到队伍全部有序。

冒泡排序的Java代码

在下列代码中,利用ArrayBub类封装了一个int型数组array[],并且对该数组的一系列操作包括冒泡排序:

class ArrayBub {    private int[] array;    private int nItem;    public ArrayBub(int max) {        array = new int[max];        nItem = 0;    }    public void bubbleSort() {        for(int out = nItem-1; out  > 1; out --) {//记录第nItem-out趟排序            for(int in = 0; in < out ; in ++) {//记录第in+1次比较                if(array[in] > array[in+1]) {                    swap(in, in+1);                }            }        }    }    public void swap(int a, int b) {        int temp;        temp = array[a];        array[a] = array[b];        array[b] = temp;    }    //其它查找、删除等操作与之前的无序数组相同    ...}//end ArrayBub

为了清晰可见,上述代码将交换的部分用一个方法swap独立出来,但是实际上,使用一个独立的swap方法并不一定好,因为这会产生一些额外的消耗,所以自己写代码时最好把这部分直接放在程序中。

不变性

在许多算法当中,有些条件是不变的,这些不变的条件被称为不变性。认识这些不变性对于我们理解算法和调试程序有用。
在冒泡排序中,不变性是指out右边的所有数据的排列是有序的,在整个算法执行过程中这个条件始终为真。

冒泡排序的效率

如果有10个学生进行排序,那么按照冒泡排序,第一趟需要9次比较,第二趟需要8次比较,以此类推,最后一趟需要1次比较,所以对于10个数据项,要进行9+8+7+6+5+4+3+2+1=(9+1)*9/2次比较
一般来说对于N个数据项则总共要进行如下次比较:
(N-1)+(N-2)+…+2+1=(N-1)*N/2
这样算法总共进行约(N^2)/2次比较(忽略减1,不会差别很大,特别是当N很大的时候)
冒泡排序的交换次数总是要少于或等于比较次数,如果数据是随机的,那么大概有一半的数据要进行交换,即要进行(N^2)/4次交换(除非在最坏的情况,初始数据是逆序排列的,那么此时每一次比较之后都要进行一次交换)
冒泡排序的交换和比较都是和(N^2)成正比,因为在大O表示法中,不需要常数,所以此处的2和4可以忽略,所以冒泡排序的运行时间是O(N^2)级的,由此可见冒泡排序的效率很低。
无论何时,我们只要看到一个循环嵌套着另一个循环的算法,就可以怀疑该算法是O(N^2)级的,外层循环要进行N次,内层循环对于每次的外层循环都要执行N次(或几分之N次),这就意味着要执行N*N次某个操作。

0 0