直接插入排序
直接插入排序(Straight Insertion Sort)的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表。开始时有序表中只包含1个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。
public static void insertSort(int[] array){
int bound = 1;
for ( ; bound < array.length; bound++){
int tmp = array[bound];
int cur = bound - 1;
for( ; cur >= 0; cur--){
if(array[cur] > tmp){
array[cur + 1] = array[cur];
}else{
break;
}
}
array[cur + 1] = tmp;
}
}
空间复杂度: | O(1) | ||
---|---|---|---|
时间复杂度: | 最好O(n) | 平均 O(n²) | 最坏O(n²) |
稳定性: | 稳定 | – |
插入排序,初始数据越接近有序,时间效率越高。如果当前序列很短,插入排序效率也很高。
希尔排序
把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的元素越来越多,当增量减至1时,整个区间恰被分成一组,算法便终止。
希尔排序是对直接插入排序的优化。当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
public static void shellSort(int []array) {
int gap = array.length;
while (gap > 1) {
gap /= 2;
}
insertSortGap(array,gap);
}
public static void insertSortGap(int[] array,int gap){
int bound = 1;
for(; bound < array.length; bound++){
int tmp = array[bound];
int cur = bound - gap;
for(; cur >=0; cur--){
if(array[cur] > tmp){
array[cur + gap] = array[cur];
}else{
break;
}
}
array[cur+gap] = tmp;
}
}
空间复杂度: | O(1) | ||
---|---|---|---|
时间复杂度: | 最好O(n) | 平均 O(n^1.3) | 最坏O(n²) |
稳定性: | 不稳定 | – |
直接选择排序
每一次从无序区间选出最大(或最小)的一个元素,存放在无序区间的最后(或最前) ,直到全部待排序的数据元素排完 。
public static void selectSort(int[]array){
for(int bound = 0; bound < array.length; bound++){
for(int cur = bound + 1; cur < array.length; cur++){
int tmp = array[bound];
if(array[cur] < tmp){
array[bound] = array[cur];
array[cur] = tmp;
}
}
}
}
空间复杂度: | O(1) |
---|---|
时间复杂度: | O(n) |
稳定性: | 不稳定 |
堆排序
首先用给定得元素建立堆(①完全二叉树②父节点值>子节点值),堆建立成功,交换第一个和最后一个元素,然后这个最后一个元素就算排序成功了。
public static void heapSort(int[] array){
creatHeap(array);
for(int i = 0; i < array.length; i++){
swap(array, array.length - i-1, 0);
shiftDown(array,array.length -1 -i, 0);
}
}
public static void creatHeap (int[] array){
for(int i = (array.length-1-1)/2 ; i>=0; i--){
shiftDown(array, array.length, i);
}
}
public static void shiftDown(int[] array, int size, int index){
int parent = index;
int child = 2 * parent + 1;
while(child < size){
if(child + 1 < size && array[child + 1] > array[child]){
child = child + 1;
}
if(array[parent] < array[child]){
swap(array, child, parent);
}else{
break;
}
parent = child;
child = 2 * parent +1;
}
}
public static void swap(int[] array, int x, int y){
int tmp = array[x];
array[x] = array[y];
array[y] = tmp;
}
空间复杂度: | O(1) |
---|---|
时间复杂度: | O(n * log(n)) |
稳定性: | 不稳定 |
冒泡排序
在无序区间,通过相邻数的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有序
public static void bubbleSort(int[] arr){
for(int i = 0; i < arr.length; i++){
for(int j = i +1 ; j < arr.length; j++){
if(arr[i] > arr[j]){
swap(arr, i, j);
}
}
}
}
public static void swap(int[] array, int x, int y){
int tmp = array[x];
array[x] = array[y];
array[y] = tmp;
}
空间复杂度: | O(1) | ||
---|---|---|---|
时间复杂度: | 最好O(n) | 平均 O(n²) | 最坏O(n²) |
稳定性: | 稳定 | – |
快速排序
选择一个基准数,通过一趟排序将要区间分成两部分。其中一部分的所有数据都比另外一部分小。然后,在按此方法对这两部分数据进行快排,整个排序过程可以递归进行。
public static void quickSort(int[] array, int left, int right ){
if(left < right){
int i = left;
int j = right;
int baseValue = array[i];
while ( i < j){
while( i < j && array[j] > baseValue){
j--; // 从右向左找第一个小于baseValue的值
}
if(i<j){
array[i++] = array[j];
}
while (i < j && array[i] < baseValue){
i++;
}
if(i<j){
array[j--]=array[i];
}
}
array[i] = baseValue;
quickSort(array,left,i-1);
quickSort(array,i+1,right);
}
}
空间复杂度: | 最好O(log(n)) | 平均O(log(n)) | 最坏O(n) |
---|---|---|---|
时间复杂度: | 最好O(n * log(n)) | 平均O(n * log(n)) | 最坏O(n^2) |
稳定性: | 不稳定 | – |
归并排序
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子 序列段间有序。
使用递归
public class Sort {
public static void mergeSort(int[] array) {
mergeSortHelper(array, 0, array.length);
}
private static void mergeSortHelper(int[] array, int left, int right) {
if (left >= right || right - left == 1) {
return;
}
int mid = (left + right) / 2;
mergeSortHelper(array, left, mid);
mergeSortHelper(array, mid, right);
merge(array, left, mid, right);
}
private static void merge(int[] array, int left, int mid, int right) {
int length = right - left;
int[] temp = new int[length];
int tempIndex = 0;
int i = left;
int j = mid;
while (i < mid && j < right) {
//加入 = 使得数据稳定
if (array[i] <= array[j]) {
temp[tempIndex++] = array[i++];
}else {
temp[tempIndex++] = array[j++];
}
}
while (i < mid) {
temp[tempIndex++] = array[i++];
}
while (j < right) {
temp[tempIndex++] = array[j++];
}
for (int k = 0; k < length; k++) {
array[left + k] = temp[k];
}
}
public static void main(String[] args) {
int[] arr = {9, 5, 2, 7, 3, 6, 1, 8};
mergeSort(arr);
System.out.println(Arrays.toString(arr));
}
}
不使用递归
public static void mergrSortByLoop(int[] array) {
for (int i = 1; i < array.length; i = i * 2) {
for (int j = 0; j < array.length; j = j+ 2 * i) {
int low = j;
int mid = j + i;
if (mid >= array.length) {
continue;
}
int high = mid + 1;
if (high > array.length) {
high = array.length;
}
merge(array, low, mid, high);
}
}
}
空间复杂度: | O(n) |
---|---|
时间复杂度: | O(n * log(n)) |
稳定性: | 稳定 |