本文均为升序算法
简单选择排序
- 将序列最小(or最大)值元素放在待排序序列首位,
- 从剩余待排序序列中选最小(or最大)元素,放在待排序序列首位(也就是总序列的第二个位置),
- 以此类推。。。
public static void simpleSelectSort(int[] array) {
int len = array.length;
int temp = 0;
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len; j++) {
//始终用待排序列的首位元素与后面的元素比较
if (array[i] > array[j]) {
//交换元素
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
改进选择排序1
上述排序内循环每次都交换元素,可以改进为,只记录元素位置,内循环完成后只交换一次元素即可
public static void selectSort1(int[] array) {
int len = array.length;
int temp = 0;
int minIndex = 0;
for (int i = 0; i < len; i++) {
minIndex = i;
for (int j = i + 1; j < len; j++) {
if (array[i] > array[j]) {
minIndex = j;
}
}
if (minIndex > i) {
temp = array[i];
array[i] = array[minIndex];
array[minIndex] = temp;
}
}
改进的选择排序2
内循环从待排序数组两端开始比较,一次循环后最小、最大值分别排在两端
public static void selectSort2(int[] array) {
int len = array.length;
for (int i = 0; i < len/2 + 1; i++) {
int minIndex = i;
int maxIndex = i;
int minVal = array[minIndex];
int maxVal = array[maxIndex];
for (int j = i + 1; j < len - i; j++) {
//每一次比较,都更新最值的index,value
if (array[j] > maxVal) {
maxIndex = j;
maxVal = array[j];
}
if (array[j] < minVal) {
minIndex = j;
minVal = array[j];
}
}
int temp = 0;
if (minIndex > i) {
temp = array[minIndex];
array[minIndex] = array[i];
array[i] = temp;
}
if (maxIndex < len - 1 - i) {
temp = array[maxIndex];
array[maxIndex] = array[len - 1 - i];
array[len - 1 - i] = temp;
}
print(array);
}
}
冒泡排序
- 从序列起始位置,两两比较,符合条件就交换位置,将最大值(or最小)确定在序列末尾
- 重复1的逻辑,将最值确定在序列倒数第二位
- 以此类推
public static void bubbleSort(int[] array) {
int len = array.length;
for (int i = 0; i < len; i++) {
int temp = 0;
for (int j = 0; j < len - 1- i; j++) {
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
改进的冒泡排序1
增加有序标志,比如1,2,3,4,9,6,前四个元素有序,当待排序列为1,2,3,4就可以结束了
因此增加一个数据交换标识,有数据交换表示无序,无数据交换就结束比较,选择用while控制外层循环
public static void bubbleSort1(int[] array) {
int len = array.length;
int temp = 0;
boolean flag = true;//数据交换标识,默认为有,表明待排序列无序
while(flag) {
flag = false;
for (int j = 0; j < len - 1; j++) {
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
flag = true;
}
}
len--;
}
}
冒泡排序改进2
5,3,2,8,9,10,后三个元素不用排序,因此算法中对后三个元素的比较是多余的,可以简化,记录内循环最后一次元素交换的位置,下一轮循环,以该位置作为元素比较的边界(注意是比较)
public static void bubbleSort2(int[] array) {
int len = array.length;
int flag = len;//设置待排序序列的边界,默认为整个序列
int temp = 0;
while (flag>0) {//如果flag=0,表示上一次循环没有元素交换,序列已经有序
flag = 0;
for (int i = 1; i < len; i++) {
if (array[i - 1] > array[i]) { //交换数据
temp = array[i];
array[i] = array[i-1];
array[i-1] = temp;
flag = i; //记录最新边界
}
}
len = flag;//该边界作为下一次循环的限制条件
}
}
插入排序
通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
- 从第一个元素开始,该元素可以认为已经被排序;
- 取出下一个元素,在已经排序的元素序列中从后向前扫描;
- 如果该元素(已排序)大于新元素,将该元素移到下一位置;
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
- 将新元素插入到该位置后;
重复步骤2〜5。
public static void insertionSort(int[] array) {
int len = array.length;
for (int i = 1; i < len; i++) {//从第二个数开始比较
int temp = array[i];
int index = i;
for (int j = i - 1; j >= 0; j--) {
if (array[j] > temp ) {
array[j + 1] = array[j];////注意并不需要交换元素,只需要后移
index = j;
} else {
break;//array[j+1]之前是有序序列,array[j] <= array[j+1]无须比较
}
}
if (index != i){
array[index] = temp;
}
}
希尔排序
希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
希尔排序是把记录按下表的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
我们选择增量gap=length/2,缩小增量继续以gap = gap/2的方式,这种增量选择我们可以用一个序列来表示,{n/2,(n/2)/2...1},称为增量序列,图解:

public static void shellSort(int[] array) {
int len = array.length;
for (int gap = len / 2; gap > 0; gap /= 2) {
for (int i = gap; i < len; i++) {//直接插入排序
int temp = array[i];
int index = i;
for (int j = i - gap; j >= 0; j -= gap) {
if (array[j] > temp) {
array[j + gap] = array[j];
index = j;
} else {
break;
}
}
if (index != i) {
array[index] = temp;
}
}
}
}
快速排序
快排采用分治策略,从序列中选一个基准值,将小于基准值的元素排在左边,大于基准值元素排在右边,然后对这两个子序列进行递归,最终整个序列有序
待排序列为:
35 12 99 56 0 78
i → ............. ← j
- 取首位元素为基准值(最好取中间值),设置两个指针i,j,分别标识序列首末两个元素,i,j移动方向为i++,j--
- j位元素先和基准值比较,若大于基准值,j左移(j--),直到小于基准值,赋值,i右移一位
0 12 99 56 0 78
.....i ............j - i位元素和基准值比较,若小于基准值,i右移(i++),直到大于基准值,赋值,j左移一位
0 12 99 56 99 78
......... i ..j
2.递归
public static void quickSort(int[] array) {
int len = array.length;
sort(array, 0, len - 1);
}
private static void sort(int[] src, int begin, int end){
if (begin < end) {
int key = src[begin];//将第一个数作为基准值
int i = begin;
int j = end;
while (i < j) {
while (i < j && src[j] >= key) {
j--;
}
if (i < j) {
src[i] = src[j];
i++;
}
while (i < j && src[i] < key) {
i++;
}
if (i < j) {
src[j] = src[i];
j--;
}
}
src[i] = key;
sort(src, 0, i - 1);
sort(src, i + 1, end);
}
}
各种排序的时间复杂度

网友评论