/**
* 使用逐步推导的方式来编写冒泡排序
* 冒泡排序并实现简单优化,时间复杂度O(n^2)
* 80000数据进行排序大概需要:14秒
* @param arr 传入需要排序的数组
*/
private void bubbleSort(int[] arr) {
int temp;
boolean flag = false; //表示变量,表示是否进行过交换
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
//将最大的元素排列在最后
if (arr[j] > arr[j+1]) {
flag = true; //优化部分
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
// System.out.printf("第%d趟排序\n",i+1);
// System.out.println(Arrays.toString(arr));
if (!flag) { //如果没有进行过交换,直接暂停返回
break;
} else {
flag = false; //重置flag
}
}
/*//第一趟排序,将最大的数排在最后面(要去arr.length-1个数相比较)
int temp2 = 0;
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i+1]) {
temp2 = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp2;
}
}
System.out.println("第一趟排序后的数组");
System.out.println(Arrays.toString(arr));
//第二趟排序,将最大的数排在最后面(要去arr.length-2个数相比较)
int temp3 = 0;
for (int i = 0; i < arr.length - 1 - 1; i++) {
if (arr[i] > arr[i+1]) {
temp2 = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp2;
}
}
System.out.println("第一趟排序后的数组");
System.out.println(Arrays.toString(arr));*/
}
/**
* 使用逐步推导的方式来编写选择排序
* 选择排序:时间复杂度O(n^2)
* 80000数据进行排序大概需要:3秒
* @param arr 需要排序的数组
*/
private void selectSort(int[] arr) {
int minIndex; //数组中每一轮最小值的下标
int min; //数组中每一轮的最小值
for (int i = 0; i < arr.length - 1; i++) {
minIndex = i;
min = arr[i];
for (int j = i + 1; j < arr.length; j++) {
if (min > arr[j]) {
min = arr[j]; //每一轮重置min的值,使其成为最小值
minIndex = j; //每一轮重置minIndex的值,找到最小值的那个数组下标
}
}
if (minIndex != i) {
//将最小值与前面的arr[i]进行替换
arr[minIndex] = arr[i];
arr[i] = min;
}
}
/*//第一轮
int minIndex = 0;
int min = arr[0];
//与后面的arr.length-1个数相比较,选出最小的数放到最前面
for (int i = 0 + 1; i < arr.length; i++) {
if (min > arr[i]) { //说明假定的最小值,并不是最小
min = arr[i]; //重置min
minIndex = i; //重置minIndex
}
}
//如果最小的数不是arr[0]就进行交换
if (minIndex != 0) {
//遍历过后min就是最小的值,i就是对应的最小值的坐标,与第一个位置进行交换
arr[minIndex] = arr[0];
arr[0] = min;
}
//第二轮
minIndex = 1;
min = arr[1];
//与后面的arr.length-1个数相比较,选出最小的数放到最前面
for (int i = 1 + 1; i < arr.length; i++) {
if (min > arr[i]) { //说明假定的最小值,并不是最小
min = arr[i]; //重置min
minIndex = i; //重置minIndex
}
}
//如果最小的数不是arr[0]就进行交换
if (minIndex != 1) {
//遍历过后min就是最小的值,i就是对应的最小值的坐标,与第一个位置进行交换
arr[minIndex] = arr[0];
arr[0] = min;
}*/
}
private void insertSort(int[] arr) {
/*
* 实现思路参考下面的分布
* 使用逐步推导的方式来编写插入排序:使用Debug可以观察其变化
* 80000数据进行排序大概需要:1秒
*/
for (int i = 1; i < arr.length; i++) {
int insertVal = arr[i];
int insertIndex = i - 1;
while (insertIndex >= 0 && insertVal < arr[insertIndex]) {
arr[insertIndex + 1] = arr[insertIndex];
insertIndex --;
}
//当退出while循环时,说明插入位置找到,insertIndex+1
if (insertIndex + 1 != i ) { //说明并没有发生上面的while循环置换(插入排序优化)
arr[insertIndex+1] = insertVal;
}
}
/*//第一轮{34,101,119,1}
//定义待插入的数
int insertVal = arr[1];
int insertIndex = 1 - 1; //即arr[1]的前面这个数的下标
//给insertVal找到插入的位置
//说明
//1.insertIndex>=0保证在给insertVal找插入位置,不越界
// 2.insertVal= 0 && insertVal < arr[insertIndex]) {
arr[insertIndex+1] = arr[insertIndex];
insertIndex--;
}
//当退出while循环时,说明插入位置找到,insertIndex+1
arr[insertIndex+1] = insertVal;
System.out.println("第一轮排序");
System.out.println(Arrays.toString(arr));
//第二轮{34,101,119,1}
//定义待插入的数
int insertVal2 = arr[2];
int insertIndex2 = 2 - 1; //即arr[1]的前面这个数的下标
//给insertVal找到插入的位置
//说明
//1.insertIndex>=0保证在给insertVal找插入位置,不越界
// 2.insertVal= 0 && insertVal2 < arr[insertIndex2]) {
arr[insertIndex2+1] = arr[insertIndex2];
insertIndex2--;
}
//当退出while循环时,说明插入位置找到,insertIndex+1
arr[insertIndex2+1] = insertVal2;
System.out.println("第二轮排序");
System.out.println(Arrays.toString(arr));
//第三轮{1,34,101,119}
//定义待插入的数
int insertVal3 = arr[3];
int insertIndex3 = 3 - 1; //即arr[1]的前面这个数的下标
//给insertVal找到插入的位置
//说明
//1.insertIndex>=0保证在给insertVal找插入位置,不越界
// 2.insertVal= 0 && insertVal3 < arr[insertIndex3]) {
arr[insertIndex3+1] = arr[insertIndex3];
insertIndex3--;
}
//当退出while循环时,说明插入位置找到,insertIndex+1
arr[insertIndex3+1] = insertVal3;
System.out.println("第三轮排序");
System.out.println(Arrays.toString(arr));*/
}
private void shellSort(int[] arr) {
/**
* 使用逐步推导的方式来编写希尔排序
* 希尔排序:第一种方法:交换法
* 80000数据进行排序大概需要:12秒
*/
int temp = 0;
//显示每次分几次组(arr.length/2表示第一次分多少组)
for (int i = arr.length/2; i > 0; i /= 2) { //5,2,1
//i的值表示每一次分组所跨的步长
for (int j = i; j < arr.length; j++) { //i=2,j=2时,2,3,4,5,6,7,8,9
for (int k = j - i; k >= 0; k -= i) {
if (arr[k] >arr[k+i]) {
temp = arr[k];
arr[k] = arr[k+i];
arr[k+i] = temp;
}
}
}
}
// System.out.println(Arrays.toString(arr));
/*int temp = 0;
//希尔排序的第1轮排序
//因为第1轮排序,是将10个数据分成了5组
for (int i = 10/2; i < arr.length; i++) {
//遍历各组中所有的元素(共5组,每组有2个元素),步长为5
for (int j = i - 5; j >= 0; j -= 5) {
if (arr[j] > arr[j + 5]) {
temp = arr[j];
arr[j] = arr[j + 5];
arr[j + 5] = temp;
}
}
}
System.out.println("希尔排序第一轮"); //[3, 5, 1, 6, 0, 8, 9, 4, 7, 2]
System.out.println(Arrays.toString(arr));
//希尔排序的第2轮排序
//因为第1轮排序,是将10个数据分成了5/2 = 2组
for (int i = 5/2; i < arr.length; i++) {
//遍历各组中所有的元素(共2组,每组有5个元素),步长为2
for (int j = i - 2; j >= 0; j -= 2) {
if (arr[j] > arr[j + 2]) {
temp = arr[j];
arr[j] = arr[j + 2];
arr[j + 2] = temp;
}
}
}
System.out.println("希尔排序第二轮"); //[0, 2, 1, 4, 3, 5, 7, 6, 9, 8]
System.out.println(Arrays.toString(arr));*/
}
/*
* 使用移位法进行希尔排序:将希尔排序与插入排序相结合
* 80000数据进行排序大概需要:1秒
*/
private void shellSort(int[] arr) {
//增量gap
for (int gap = arr.length / 2;gap > 0;gap /= 2) {
//从第gap个元素,逐个对其所在的组进行直接插入排序
for (int i = gap; i < arr.length; i++) {
//使用插入排序的算法
int j = i;
int temp = arr[j];
if (arr[j] < arr[j-gap]) {
while (j - gap >= 0 && temp < arr[j-gap]) {
//移动
arr[j] = arr[j-gap];
j -= gap;
}
//当while循环退出时,就给temp找到插入的位置
arr[j] = temp;
}
}
}
// System.out.println(Arrays.toString(arr));
}
快速排序法介绍
快速排序(Quicksort)是对冒泡排序的一种改进。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
代码实现
要求:对[-9,78,0,23-567,70]进行从小到大的排序,要求使用快速排序法。【测试8w和800w】
说明[验证分析]:
1)如果取消左右递归,结果是 -9,-567,0,23,78,70
2)如果取消右递归,结果是 -567,-9,0,23,78,70
3)如果取消左递归,结果是 -9,-567,0,23,70,8
/**
* 快速排序:速度非常快,对8000000的大小数组进行排序只需要1秒钟
* 此方法是以中间的那个只为基准
* @param arr 排序的数组
* @param left 左索引
* @param right 右索引
*/
private void quickSort(int[] arr,int left,int right) {
int l = left; //左下标
int r = right; //右下标
//pivot 中轴值
int pirvot = arr[(left + right) / 2];
int temp = 0; //临时变量
//while循环的目的是让比pivot值小的放到左边,比pivot值大的放到右边
while (l <r) {
//在pivot左边一直找,直到找到大于等于pivot的值,才能退出
while (arr[l] < pirvot) {
l += 1;
}
//在pivot右边一直找,直到找到小于等于pivot的值,才能退出
while (arr[r] > pirvot) {
r -= 1;
}
//对上面的两个循环条件进行终止(当都左右索引已经遍历超过中间时,进行break)
if (l >= r) {
break;
}
//交换
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
//如果交换完后,发现这个arr[l] == pivot值相等 r--,前移
if (arr[l] == pirvot) {
r -= 1;
}
//如果交换完后,发现这个arr[r] == pivot值相等 l++,后移
if (arr[r] == pirvot) {
l += 1;
}
}
//如果 l == r,必须l++,r--,否则会出现栈溢出
if (l == r) {
l += 1;
r -= 1;
}
//向左递归
if (left < r) {
quickSort(arr,left ,r );
}
//向右递归
if (right > l) {
quickSort(arr,l ,right );
}
}