JAVA数据结构和算法——简单排序
2018-08-24 本文已影响0人
往昔負流年
冒泡排序
/**
* 冒泡排序
* 需要N*(N-1)/2约等于N*N/2次比较,因为满足条件才交换所以交换的次数少于比较的次数
* 如果数据是随机的那么大概一半数据需要交换,则交换次数为N*N/4。
* 交换和比较操作次数都和N*N成正比。常数不算在大O表示法中可以忽悠2和4,
* 所以冒泡排序运行需要O(N*N)时间级别。
* 不变性:out右边的数据总是有序的
* 个人理解:N*N/2次比较+交换次数为N*N/4
* @param arr
*/
public void bubbleSort(int[] arr) {
int length = arr.length;
for(int out = length-1; out > 0; out--) {
//下标大于out的数据是已经排好序了的所以没有必要比较交换
for(int in = 0; in < out; in++) {
//比较
if(arr[in] > arr[in+1]) {
//如果满足左边大于右边则交换
int temp = arr[in];
arr[in] = arr[in+1];
arr[in+1] = temp;
}
}
}
}
选择排序
/**
* 选择排序
* 选择排序和冒泡排序执行了相同次数的比较:N*(N-1)/2。
* N值很大时,比较次数是主要的,所以结论是选择排序和冒泡排序一样运行了O(N*N)时间。
* 但是选择排序无疑更快,因为他进行交换次数少的多(O(N))。
* 当N值较小时,特别是如果交换时间级比比较时间级大得多时,选择排序实际上是相当快的。
* 不变性:out左边的数据总是有序的
* 个人理解:其实是N*(N-1)/2次比较+(O(N))次交换+N*(N-1)/4复制
* @param arr
*/
public void selectionSort(int[] arr) {
for(int out = 0; out < arr.length - 1; out++) {
//寻找最小值的下标
int min = out;
for(int in = out + 1; in < arr.length; in++) {
if(arr[in] < arr[min]) {
//其实按照个人理解这个需要N*(N-1)/4复制
min = in;
}
}
//把最小放在最左边
int temp = arr[min];
arr[min] = arr[out];
arr[out] = temp;
}
}
插入排序
/**
* 插入排序
* 不变性:在每趟结束结束时,在讲temp位置的项插入后,比out变量下标小的数据项都是局部有序的。
* 效率:在第一趟排序中最多比较一次,第二趟最多比较两次,以此类推最后一躺最多比较N-1次。
* 因此1+2+3+...+N-1 = N*(N-1)/2,然而因为在每一趟排序发现插入点之前,平均只有全体数据项的一半
* 真的进行了比较,我们除以2得到N*(N-1)/4.
* 复制次数大致等于比较次数。然后一次复制与一次交换的时间耗费不同,所以相对于随机数据,这个算法比冒泡排序快一倍,
* 比选择排序略快。于其他简单排序一样对于随机顺序的数据进行插入排序也需要O(N*N)的时间级。
* 对于已经有序或基本有序的数据来说,插入排序要好得多。
* 个人理解:N*(N-1)/4比较+N*(N-1)/4次复制+N次复制
* @param arr
*/
public void insertionSort(int[] arr) {
for(int out = 1; out < arr.length; out++) {
int temp = arr[out];
int in = out;
while (in > 0 && arr[in-1] >= temp) {
//个人理解这儿是N*(N-1)/4次复制
arr[in] = arr[in-1];
--in;
}
//个人理解这儿是N次复制
arr[in] = temp;
}
}
排序算法的选择
除非手边没有算法书可参考,一般情况几乎不太用冒泡排序。选择排序虽然把交换次数降到最低,但比较次数依然很大。当数据量很小,并且交换数据相对于比较数据更加耗时的情况下可以用选择排序。在大多数的情况下假设数据量比较小,或者基本有序时,插入排序是三种简单排序中最好的选择。对于更大数据量的排序来说,快速排序通常是更快的方法。
除了在速度方面比较排序算法外,还有一个衡量标准就是算法需要的内存空间多大。这三种算法都除了数组外几乎不需要其他的内存空间。所有排序算法都需要一个额外的变量来暂时存储变换时的数据项。