排序算法
冒泡排序
思想:把相邻的元素两两比较,当一个元素大于右侧相邻元素时,交换它们的位置!每一个循环将较大数置于右侧。时间复杂度就是O(nlogn)。
优化点:
- 每次循环后可剔除右侧一个元素就行比较
- 若一个循环下来,没有任何元素交换,说明数组有序,可直接退出
- 若循环在某个index之后,就没有进行数据交换,说明该index后的数组有序,不进入循环。
鸡尾酒排序
对冒泡排序的升级,冒泡排序始终是从左侧到右侧。鸡尾酒排序先从左到右,再从右到左,依次循环。适用于大多数元素都有序的情况。
快速排序
思想:采用分治法,选择基准元素,将比它的小的放在左边,将比它大的放在右边。 然后对左边和右边的数组继续分而治之。
public static void main(String[] args) {
int[] test = {5, 8, 6, 3, 9, 2, 1, 7};
int[] test2 = {3, 4, 2, 1, 5, 6, 7, 8};
Sort sort = new Sort();
// int[] result = sort.cocktailSort(test2);
int[] result = sort.quickSort(test2, 0, test2.length);
for (int temp : result) {
System.out.print(temp + " ");
}
}
/**
* 冒泡排序 每一次都会把数组中的最大值放到数组的最右侧。
* <p>
* 时间复杂度O(n^2)
*
* @param source
* @return
*/
public int[] bubbleSort(int[] source) {
for (int i = 0; i < source.length; i++) {
for (int j = 0; j < source.length - 1; j++) {
if (source[j] > source[j + 1]) {
int temp = source[j + 1];
source[j + 1] = source[j];
source[j] = temp;
}
}
}
return source;
}
/**
* 冒泡排序,快排每一次都会把数组中的最大值放到数组的最右侧。
* 优化项:1.每遍历一次,可以减少一个元素参与排序
* 2.若没发生元素交换,说明数据已经有序
* 3.对于本身右边有序的数组,可以不用进行排序,是1的进一步优化
*
* @param source
* @return
*/
public int[] bubbleSortV2(int[] source) {
int sortBorder = source.length - 1;
for (int i = 0; i < source.length; i++) {
boolean isSorted = true;
int sortBorder1 = sortBorder;
for (int j = 0; j < sortBorder1; j++) {
if (source[j] > source[j + 1]) {
int temp = source[j + 1];
source[j + 1] = source[j];
source[j] = temp;
isSorted = false;
sortBorder = j;
}
}
if (isSorted) {
break;
}
}
return source;
}
/**
* 鸡尾酒排序,对冒泡排序的优化。针对大部分
* <p>
* 冒泡排序是单向的,鸡尾酒排序可以改成双向的
*
* @param source
* @return
*/
public int[] cocktailSort(int[] source) {
int sortBorder = source.length - 1;
for (int i = 0; i < source.length; i++) {
int sortBorder1 = sortBorder;
boolean isSorted = true;
if (i % 2 == 0) {
for (int j = 0; j < sortBorder1; j++) {
if (source[j] > source[j + 1]) {
int temp = source[j + 1];
source[j + 1] = source[j];
source[j] = temp;
isSorted = false;
sortBorder = j;
}
}
} else {
for (int j = sortBorder1; j > 0; j--) {
if (source[j] < source[j - 1]) {
int temp = source[j - 1];
source[j - 1] = source[j];
source[j] = temp;
isSorted = false;
}
}
}
if (isSorted) {
break;
}
}
return source;
}
/**
* 快速排序,选择基准元素,将小于它的元素放在右边,大于它的元素放在左边。
* 不断二分,直到有序。也叫做分治法
* 时间复杂度:O(nlogn)
*
* @param array
* @param startIndex
* @param endIndex
* @return
*/
public int[] quickSort(int[] array, int startIndex, int endIndex) {
if (startIndex >= endIndex) {
return array;
}
int divide = partitionV2(array, startIndex, endIndex);
quickSort(array, startIndex, divide);
quickSort(array, divide + 1, endIndex);
return array;
}
/**
* 选择基准startIndex,将比基准元素小的数移到左边,大的数移到右边,把基准元素和边界替换。
*
* @param array
* @param startIndex
* @param endIndex
* @return
*/
private int partition(int[] array, int startIndex, int endIndex) {
int base = array[startIndex];
int mark = startIndex;
for (int i = startIndex + 1; i < endIndex; i++) {
//将小于基准元素的数右移
if (array[i] < base) {
mark++;
int temp = array[mark];
array[mark] = array[i];
array[i] = temp;
}
}
// 将基准元素放到边界,完成右边比它小,左边比它大
array[startIndex] = array[mark];
array[mark] = base;
return mark;
}
/**
* 选择基准元素为startIndex,然后从右往左,比基准元素小,双方替换
* 接着再从左往右开始。
*
* @param array
* @param startIndex
* @param endIndex
* @return
*/
private int partitionV2(int[] array, int startIndex, int endIndex) {
int base = array[startIndex];
int left = startIndex;
int right = endIndex - 1;
while (left != right) {
while (right > left) {
if (array[right] < base) {
array[left] = array[right];
array[right] = base;
left++;
break;
} else {
right--;
}
}
while (right > left) {
if (array[left] > base) {
array[right] = array[left];
array[left] = base;
right--;
break;
} else {
left++;
}
}
}
return left;
}
本文为学习笔记,参考博客为小灰的博客:https://blog.csdn.net/bjweimengshu/article/details/103573147