赞
踩
对数据排序可能是检索的一个初始步骤,例如:二分查找法比线性查找法要快的多,然而它只能应用于有序的数据。
先介绍三种简单排序:冒泡,选择,插入。算法比较简单,执行速度也就慢一些,在某些情况下比那些复杂的算法实际上还好一些。比如小规模的文件以及基本有序的文件,插入排序算法能比快速排序算法更为有效,实际上,插入排序通常也作为快速排序算法实现的一部分。
简单排序算法大致上都包含如下操作:
package test29; /** * 冒泡排序 */ public class ArrayBub { private int[] a; //记录数组的实际长度 private int nElems; public ArrayBub(int max) { a = new int[max]; nElems = 0; } /** * 插入操作 * * @param value */ public void insert(int value) { a[nElems] = value; nElems++; } /** * 展示 */ public void display() { for (int i = 0; i < nElems; i++) { System.out.print(a[i] + " "); } System.out.println(); } public void bubbleSort() { int out, in; int temp; for (out = nElems - 1; out > 0; out--) { for (in = 0; in < out; in++) { if (a[in] > a[in + 1]) { temp = a[in]; a[in] = a[in + 1]; a[in + 1] = temp; } } } } }
package test29; /** * 冒泡排序 */ public class BubbleSortApp { public static void main(String[] args) { int maxSize = 100; ArrayBub arr = new ArrayBub(maxSize); arr.insert(99); arr.insert(88); arr.insert(77); arr.insert(66); arr.insert(55); arr.insert(44); arr.insert(33); arr.insert(22); arr.insert(11); arr.insert(00); arr.display(); arr.bubbleSort(); arr.display(); } }
out右边的所有数据项是有序的
一般来说,数组中有N个数据项,则第一遍排序中有N-1次比较,第二遍有N-2次,如此类推
(N-1)+(N-2)+(N-3)+…+1=N*(N-1)/2
这样算法做了约N²/2次比较。
当比较的两个元素,左边大于右边时,需要交换,否则不交换。
如果数据是随机的,大约有一半的元素可能需要交换,则交换的次数为N²/4
交换和比较的次数都和N²成正比,使用大O表示法可知冒泡排序法的时间复杂度为O(N²)
对冒泡排序法进行改进,将交换次数从O(N²)减少到O(N),而比较次数仍然是O(N²)
package test31; /** * 选择排序 */ public class ArraySelect { private int[] a; //记录数组的实际长度 private int nElems; public ArraySelect(int max) { a = new int[max]; nElems = 0; } /** * 插入操作 * * @param value */ public void insert(int value) { a[nElems] = value; nElems++; } /** * 展示 */ public void display() { for (int i = 0; i < nElems; i++) { System.out.print(a[i] + " "); } System.out.println(); } public void selectionSort() { int out, in, min; int temp; for (out = 0; out < nElems-1; out++) { //每次以out索引记为最小 min = out; for (in = out+1; in < nElems; in++) { //每次找到最小的 if (a[in] < a[min]) { min = in; } } //里层循环完毕,将最小值的索引位置上的数据和out索引位置的数据进行交换 //因此交换的次数成了O(N),这就是比冒泡排序优越的地方 temp = a[out]; a[out] = a[min]; a[min] = temp; } } }
package test31; /** * 选择排序 */ public class SelectionSortApp { public static void main(String[] args) { int maxSize = 100; ArraySelect arr = new ArraySelect(maxSize); arr.insert(99); arr.insert(88); arr.insert(77); arr.insert(66); arr.insert(55); arr.insert(44); arr.insert(33); arr.insert(22); arr.insert(11); arr.insert(00); arr.display(); arr.selectionSort(); arr.display(); } }
左侧的数据总是有序的,即下标小于或等于out的位置的数据项总是有序的
选择排序和冒泡排序执行了相同次数的比较:N*(N-1)/2.但选择排序更快,因为它进行的交换次数少的多。
使用大O表示法可知选择排序法的时间复杂度为O(N²)
package test32; /** * 插入排序 */ public class ArrayInsert { private int[] a; //记录数组的实际长度 private int nElems; public ArrayInsert(int max) { a = new int[max]; nElems = 0; } /** * 插入操作 * * @param value */ public void insert(int value) { a[nElems] = value; nElems++; } /** * 展示 */ public void display() { for (int i = 0; i < nElems; i++) { System.out.print(a[i] + " "); } System.out.println(); } public void insertionSort() { int out, in; int temp; //out变量从1开始,向右移动,他标记了未排序部分的最左端的数据 for (out = 1; out < nElems; out++) { temp = a[out]; in = out; //in变量从out变量开始,向左移动,直到temp变量小于in所指的数组数据项 //或者它已经不能向左移动为止。 //while循环的每一趟都向右移动了一个已排序的数据项 while (in > 0 && a[in - 1] >= temp) { a[in] = a[in - 1]; --in; } a[in] = temp; } } }
package test32; /** * 插入排序 */ public class InsertionSortApp { public static void main(String[] args) { int maxSize = 100; ArrayInsert arr = new ArrayInsert(maxSize); arr.insert(99); arr.insert(88); arr.insert(77); arr.insert(66); arr.insert(55); arr.insert(44); arr.insert(33); arr.insert(22); arr.insert(11); arr.insert(00); arr.display(); arr.insertionSort(); arr.display(); } }
每一趟结束后,在将temp位置的项插入后,比outer变量下标小的数据项都是局部有序的。
在第一趟排序中,它比较1次,第二趟比较2次,以此类推,第N趟,比较N-1次,因此N*(N-1)/2
实际情况下,如果是随机的数据,平均有一半的需要比较,所以N*(N-1)/4。
复制的次数大致等于比较的次数。但是,一次复制与一次交换的时间耗费不同,所以相对于随机数据,这个算法比冒泡排序快一倍,比选择排序略快。
时间复杂度也是O(N²)
对于已经有序或基本有序的数据来说,插入排序要好得多。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。