一、排序算法
1 冒泡排序
当有一串无需数列待排序时,那么冒泡排序就会每次挑选出最大的数,置于这串数的末尾,然后从剩下的数中再挑选出最大的放置在末尾(这里的末尾应当指当前剩余未排列数组的末尾,即上次排好的数之前)。重复上述过程,直到最后一个数被排完。所以冒泡排序的时间复杂度为O()
冒泡排序的示例代码如下所示:
public static void sort(int[] array) {
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
2 插入排序
插入排序是一种最简单的排序,即在一组无序数列中,将数列分成有序和无序两部分,一般默认第一个数为已序,将第二个数按照排序准则插入已序数列,再将第三个数插入前两个数组成的已序数列,重复。直到最后一个数被插入,插入排序的时间复杂度为O()。插入排序的图形表示如下所示:
代码示例如下所示:
public static int[] insertSort(int[] array) {
for (int index = 0; index < array.length; index++) {
int temp = array[index]; //将index位的数据拿出来,放到临时变量里,这时index位置就空出来了.
int leftIndex = index - 1;
while (leftIndex >= 0 && array[leftIndex] > temp) { //开始将左面的数据与当前index位的数据(即temp)进行比较
array[leftIndex + 1] = array[leftIndex];
leftIndex--;
}
array[leftIndex + 1] = temp;
}
return array;
}
3 快排
快速排序是通过一次分割将一个数列分割成以某个数为界限的左右两部分,一边数小于这个分界值,另一边大于这个分界值。分别再将两遍的数,按照同样的方法各选取一个分界值,分成大于和小于分界值的两部分,依次类推,直到分界值左右部分的数不可再分为止,快排的时间复杂度为O(nlogn)。快排的图形示例如下所示:
代码示例如下所示,这里的quicSort方法中的low是0,high是array中的尾元素:
public static int getIndex(int[] array, int low, int high) {
int temp = array[low]; //记录一个标值的值
while (low < high) {
while (low < high && array[high] > temp) high--; //1. 队尾元素大于基准元素的时候 high--
array[low] = array[high]; // 如果队尾元素小于tmp了,需要将其赋值给low
while (low < high && array[low] < temp) low++; //2. 队首元素小于基准元素的时候 low++
array[high] = array[low]; // 当队首元素大于tmp时,需要将其赋值给high
}
array[low] = temp;
return low;
}
public static void quickSort(int[] array, int low, int high) {
if (low < high) {
int index = getIndex(array, low, high);
quickSort(array, low, index - 1);
quickSort(array, index + 1, high);
}
}
4 归并排序
分治递归的思路,把序列分为两个部分,然后继续把两个序列分为四个序列,继续分… 直到最后,我们会用一个个长度 <= 1 的序列来把整个序列进行存储,之后我们再向上返回。在向上返回的过程中,我们把分出来的 左、右两个序列的元素,一一进行比较,并放入到一个新的序列中,两个序列比较完毕后,新的序列就是这两个序列排序后的合并序列。我们把新的序列向上返回,这样新的序列就会与其它二分出来的序列进行继续进行比较。直到向上返回完毕,返回出来的新序列就是原本序列排序后的序列。归并排序的时间复杂度为O(nlogn),示例图如下所示:
示例代码如下所示:
public static void mergeArray(int[] array, int low, int mid, int high) {
int[] temp = new int[array.length];
int i = low; //i右数组第一个元素索引
int j = mid + 1; //j左数组的第一个元素索引
int k = 0;// k 记录临时数组的索引
// 从两个数组中取出最小的放入临时数组
while (i <= mid && j <= high) {
if (array[i] > array[j]) temp[k++] = array[j++];
else temp[k++] = array[i++];
}
// 剩余部分依次放入临时数组(实际上两个while只会执行其中一个)
while (i <= mid) temp[k++] = array[i++];
while (j <= high) temp[k++] = array[j++];
// 将临时数组中的内容拷贝回原数组中
for (int x = 0; x < k; x++) array[x + low] = temp[x];
}
public static void mergeSort(int[] array, int low, int high) {
if (low < high) {
int mid = (low + high) / 2; // 找出中间索引
mergeSort(array, low, mid); // 对左边数组进行递归
mergeSort(array, mid + 1, high); // 对右边数组进行递归
mergeArray(array, low, mid, high); // 合并
}
}
5 选择排序
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。选择排序的思想其实和冒泡排序有点类似,都是在一次排序后把最小的元素放到最前面,或者将最大值放在最后面。但是过程不同,冒泡排序是通过相邻的比较和交换。而选择排序是通过对整体的选择,每一趟从前往后查找出无序区最小值,将最小值交换至无序区最前面的位置,选择排序的时间复杂度是O()。图形示例如下所示:
代码示例如下所示:
public static void selection_sort(int[] arr) {
int i, j, min, temp, len = arr.length;
for (i = 0; i < len - 1; i++) {
min = i;
for (j = i + 1; j < len; j++)
if (arr[min] > arr[j])
min = j;
temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
}
}