- 冒泡排序
持续比较相邻元素,大的放到后面,所以大的会逐步往后放,所以称之为冒泡排序
package com.itstyle.seckill.common.algorithm;
/**
* 冒泡排序
*/
public class BubbleSort {
/**
* 冒泡排序,持续比较相邻元素,大的挪到后面,因此大的会逐步往后挪,故称之为冒泡。
* 复杂度分析:平均情况与最坏情况均为 O(n^2), 使用了 temp 作为临时交换变量,空间复杂度为 O(1).
*/
public static void main(String[] args) {
int[] list = {27, 76, 47, 23, 7, 32, 19, 86};
System.out.println("************冒泡排序************");
System.out.println("排序前:");
display(list);
System.out.println("排序过程:");
bubbleSort(list);
// display(list);
}
/**
* 遍历打印
*/
public static void display(int[] list) {
if (list != null && list.length > 0) {
for (int num : list) {
System.out.print(num + " ");
}
System.out.println("");
}
}
/**
* 冒泡排序算法
*/
public static void bubbleSort(int[] list) {
int len = list.length;
// 做多少轮排序(最多length-1轮)
for (int i = 0; i < len - 1; i++) {
// 每一轮比较多少个
for (int j = 0; j < len - 1 - i; j++) {
if (list[j] > list[j + 1]) {
// 交换次序
int temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
System.out.print("第"+(i+1)+"轮比较过程: ");
display(list);
}
System.out.print("第"+(i+1)+"轮比较结果:");
display(list);
}
}
}
解析:第一轮比较7次从第一位比较到最后一位 是 27与76 结果不换位置(第一位与第二位比较); 76与47比较 交换位置(第二位与第三位比较)76>47,47 76;接着是76与23比较(第三位与第四位)76>23交换位置 23 76;76与7比较(第四位与第五位)76>7 交换位置得到 7 76;76与32比较(第五位与第六位)76>32得到结果 32 76;76与19比较(第六位与第七位)76>19得到结果 19 76;76与86比较(第七位与第八位)76<86不换位置。
第二轮 比较6次,从第一位比较到第七位(倒数第二位),比较过程参考第一轮
第三轮 比较5次,从第一位比较到第六位(倒数第三位),比较过程同第一轮
依次直到结束
https://www.cnblogs.com/jingmoxukong/p/4329079.html
- 直接插入排序
是一种最简单的排序方法,它的基本操作是将一个元素插入到已经排好的表中,从而得到一个新的、元素数增加1的有序表。即将插入的当前的元素的前面的元素都是有序的,要插入时,从当前这个元素的左边开始往前找(从后往前),比当前这个元素大的元素均往右移一个位置,最后把当前元素放在它应该放的位置保证是有序的。
package com.itstyle.seckill.common.algorithm;
/**
* 直接插入排序
*/
public class InsertSort {
/**
* 直接插入排序是一种最简单的排序方法,它的基本操作是将一个记录插入到已排好的有序的表中,从而得到一个新的、记录数增1的有序表。
* 当前元素的前面元素均为有序,要插入时,从当前元素的左边开始往前找(从后往前找),比当前元素大的元素均往右移一个位置,最后把当前元素放在它应该呆的位置就行了。
* 参考:https://www.cnblogs.com/mengdd/archive/2012/11/24/2786490.html
*/
public static void main(String[] args) {
int[] list = {27, 76, 47, 23, 7, 32, 19, 86};
System.out.println("************直接插入排序************");
System.out.println("排序前:");
display(list);
// System.out.println("排序后:");
insertSort(list);
// display(list);
}
/**
* 直接插入排序算法
*/
public static void insertSort(int[] list) {
int len = list.length ;
// 从无序序列中取出第一个元素 (注意无序序列是从第二个元素开始的)
for (int i = 1; i < len; i++) {
int temp = list[i];
int j;
// 遍历有序序列
// 如果有序序列中的元素比临时元素大,则将有序序列中比临时元素大的元素依次后移
for (j = i - 1; j >= 0 && list[j] > temp; j--) {
list[j + 1] = list[j];
}
// 将临时元素插入到腾出的位置中
list[j + 1] = temp;
System.out.println("排序过程从第"+(i+1)+"位与前"+i+"位比较结果如下:");
display(list);
}
}
/**
* 遍历打印
*/
public static void display(int[] list) {
if (list != null && list.length > 0) {
for (int num :list) {
System.out.print(num + " ");
}
System.out.println("");
}
}
}
快速排序
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的数据都要小,然后再按此方法对这两部分进行快速排序,整个排序过程可以递归进行,达到排序的过程。
package com.itstyle.seckill.common.algorithm;
/**
* 快速排序
*/
public class QuickSort {
/**
* 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
*/
public static void main(String[] args) {
int[] list = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8};
System.out.println("************快速排序************");
System.out.println("排序前:");
display(list);
System.out.println("排序后:");
quickSort(list, 0, list.length - 1);
display(list);
}
/**
* 快速排序算法
*/
public static void quickSort(int[] list, int left, int right) {
if (left < right) {
// 分割数组,找到分割点
int point = partition(list, left, right);
// 递归调用,对左子数组进行快速排序
quickSort(list, left, point - 1);
// 递归调用,对右子数组进行快速排序
quickSort(list, point + 1, right);
}
}
/**
* 分割数组,找到分割点
*/
public static int partition(int[] list, int left, int right) {
// 用数组的第一个元素作为基准数
int first = list[left];
while (left < right) {
System.out.println("left:"+left+":"+"right:"+right+" "+list[right]+">="+first);
while (left < right && list[right] >= first) {
right--;
System.out.println("右分割点right:"+right+"左分割点left:"+left+" "+list[right]+">="+first);
}
System.out.println("右分割点right:"+right+"左分割点left:"+left+" list[right]:"+list[right]+" list[left]"+list[left]);
// 交换
swap(list, left, right);
System.out.println();
System.out.println("left: "+left+":"+"right: "+right+" "+list[left]+"<="+first);
while (left < right && list[left] <= first) {
left++;
System.out.println("右分割点right:"+right+"左分割点left:"+left+" "+list[left]+"<="+first);
}
System.out.println("右分割点right:"+right+"左分割点left:"+left+" list[right]:"+list[right]+" list[left]"+list[left]);
// 交换
swap(list, left, right);
System.out.println();
}
// 返回分割点所在的位置
return left;
}
/**
* 交换数组中两个位置的元素
*/
public static void swap(int[] list, int left, int right) {
int temp;
if (list != null && list.length > 0) {
temp = list[left];
list[left] = list[right];
list[right] = temp;
System.out.println("将list[left]与list[right]交换位置后的排序结果:");
display(list);
}
}
/**
* 遍历打印
*/
public static void display(int[] list) {
if (list != null && list.length > 0) {
for (int num :list) {
System.out.print(num + " ");
}
System.out.println("");
}
}
}
归并排序:
package com.itstyle.seckill.common.algorithm;
/**
* 归并排序
*/
public class MergeSort {
/**
* 归并排序(Merge Sort)与快速排序思想类似:将待排序数据分成两部分,继续将两个子部分进行递归的归并排序;然后将已经有序的两个子部分进行合并,最终完成排序。
* 其时间复杂度与快速排序均为O(nlogn),但是归并排序除了递归调用间接使用了辅助空间栈,还需要额外的O(n)空间进行临时存储。从此角度归并排序略逊于快速排序,但是归并排序是一种稳定的排序算法,快速排序则不然。
* 所谓稳定排序,表示对于具有相同值的多个元素,其间的先后顺序保持不变。对于基本数据类型而言,一个排序算法是否稳定,影响很小,但是对于结构体数组,稳定排序就十分重要。例如对于student结构体按照关键字score进行非降序排序:
*/
public static void main(String[] args) {
int[] list = {50, 10, 90, 30, 70};
System.out.println("************归并排序************");
System.out.println("排序前:");
display(list);
System.out.println("排序后:rear "+(list.length - 1));
mergeSort(list, new int[list.length], 0, list.length - 1);
// display(list);
}
/**
* 归并排序算法
* @param list 待排序的列表
* @param tempList 临时列表
* @param head 列表开始位置
* @param rear 列表结束位置
*/
public static void mergeSort(int[] list, int[] tempList, int head, int rear) {
if (head < rear) {
System.out.println("head --"+head+"-- rear "+rear);
// 取分割位置
int middle = (head + rear) / 2;
System.out.println("head --"+head+" middle "+middle);
// 递归划分列表的左序列
mergeSort(list, tempList, head, middle);
System.out.println("middle 右"+(middle+1)+" rear "+rear);
// 递归划分列表的右序列
mergeSort(list, tempList, middle + 1, rear);
// 列表的合并操作
System.out.println(" head: 列表合并"+head+" middle: "+(middle+1)+" rear: "+rear);
merge(list, tempList, head, middle + 1, rear);
System.out.println();
}
}
/**
* 合并操作(列表的两两合并)
* @param list
* @param tempList
* @param head
* @param middle
* @param rear
*/
public static void merge(int[] list, int[] tempList, int head, int middle, int rear) {
//head为头 左指针尾
int headEnd = middle - 1;
// 右指针头,rear为尾
int rearStart = middle;
// 临时列表的下标
int tempIndex = head;
// 列表合并后的长度
int tempLength = rear - head + 1;
System.out.println("list --- ");
display(list);
System.out.println("tempList-- -- ");
display(tempList);
// 先循环两个区间段都没有结束的情况
while ((headEnd >= head) && (rearStart <= rear)) {
// 如果发现右序列大,则将此数放入临时列表
if (list[head] < list[rearStart]) {
System.out.println("if list[head] "+list[head]+" list[rearStart] "+list[rearStart]);
System.out.println("tempIndex "+tempIndex+" head "+head);
tempList[tempIndex++] = list[head++];
System.out.println("tempIndex "+tempIndex+" head "+head);
} else {
System.out.println("else list[head] "+list[head]+" list[rearStart] "+list[rearStart]);
System.out.println("tempIndex "+tempIndex+" rearStart "+rearStart);
tempList[tempIndex++] = list[rearStart++];
System.out.println("tempIndex "+tempIndex+" rearStart "+rearStart);
}
}
System.out.println("list --- ");
display(list);
System.out.println("tempList-- -- ");
display(tempList);
// 判断左序列是否结束
while (head <= headEnd) {
System.out.println("左序列是否结束head <= headEnd head: "+head+" headEnd: "+headEnd);
System.out.println("左序列是否结束head <= headEnd tempIndex "+tempIndex+" head "+head);
tempList[tempIndex++] = list[head++];
}
// 判断右序列是否结束
while (rearStart <= rear) {
System.out.println("右序列是否结束rearStart <= rear rearStart: "+rearStart+" rear: "+rear);
tempList[tempIndex++] = list[rearStart++];
System.out.println("右序列是否结束 tempIndex "+tempIndex+" head "+head);
}
System.out.println("list --- ");
display(list);
System.out.println("tempList-- -- ");
display(tempList);
// 交换数据
for (int i = 0; i < tempLength; i++) {
System.out.println("list[rear] "+list[rear]+" tempList[rear] "+tempList[rear]);
list[rear] = tempList[rear];
System.out.println("交换数据:执行 list[rear] = tempList[rear] 此时rear的值为:"+rear+" 交换之后的list如下:");
rear--;
display(list);
System.out.println();
System.out.println();
}
System.out.println("交换结果:");
display(list);
System.out.println("此时的rear: "+rear);
}
/**
* 遍历打印
*/
public static void display(int[] list) {
if (list != null && list.length > 0) {
for (int num :list) {
System.out.print(num + " ");
}
System.out.println("");
}
}
}
注意观察下图中控制台输出的部分middle=2时 rear=4;middle=1,rear=2;middle=0,rear=1
当不满足条件时:
下一步
不满足条件时
下一步 记得下图debug的那一部分 中middle的值为0 rear的值为 1
走完得结果为
接下来走的时下图中debug的部分此时 middle的值为1,rear=2
这部分执行完得到的结果为
下一步执行到如下图,此时 middle为2,rear为4
下一步
即得到最终结果