冒泡排序、选择排序、快速排序、插入排序
冒泡排序
package com.academicdog.sorting;
import java.util.Random;
/**
* 练习数组冒泡排序,前小后大
*
* 出现的问题:
* 1.忘记多次排序
* 2.前后弄反
* 3.从后往前的时候,arr.length忘记减1
*/
public class bubble {
public static void main(String[] args) {
Random rd = new Random();
int[] arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = rd.nextInt(99) + 1;
}
System.out.println("这是原数组:");
printArr(arr);
/*
//从前往后,把大的往后移(前面的需要多次排序)
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]){
arr[j] = arr[j] + arr[j + 1];
arr[j + 1] = arr[j] - arr[j + 1];
arr[j] = arr[j] - arr[j + 1];
}
}
}
*/
//从后往前,把小的往前(后面需要多次排序)
for (int i = 0; i < arr.length; i++) {
for (int j = arr.length - 1; j > i; j--) {
if (arr[j] < arr[j - 1]){
arr[j] = arr[j] + arr[j - 1];
arr[j - 1] = arr[j] - arr[j - 1];
arr[j] = arr[j] - arr[j - 1];
}
}
}
System.out.println("\n这是整理后的数组:");
printArr(arr);
}
public static void printArr(int[] arr){
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
选择排序
package com.academicdog.sorting;
import java.util.Random;
/**
* 练习选择排序,前小后大
*
* 出现的问题:
* 1.使用下标交换时,在交换的时候没有排除i = minN的情况,此时这两个容器一样,没法使用这种相差的方式交换,结果为0
* 2.因为出现上述情况,想到使用数字比较而不是下标,没有考虑选择排序实质是数组中两个数交换,不能用数字比较
*/
public class select {
public static void main(String[] args) {
int[] arr = createArr();
System.out.println("这是初始数组");
printArr(arr);
//选择最小的,放在最前面(使用下标)
int minIndex = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = i; j < arr.length; j++) {
if(arr[j] < arr[minIndex]){
minIndex = j;
}
}
if(i != minIndex) {
arr[i] = arr[i] + arr[minIndex];
arr[minIndex] = arr[i] - arr[minIndex];
arr[i] = arr[i] - arr[minIndex];
}
minIndex = i + 1;
}
System.out.println("\n这是处理后的数组");
printArr(arr);
}
//生成随机数组
public static int[] createArr(){
Random rd = new Random();
int[] arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = rd.nextInt(99) + 1;
}
return arr;
}
//打印数组
public static void printArr(int[] arr){
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
快速排序(见百度百科)
package com.academicdog.sorting;
import java.util.Random;
/**
* 快速排序算法通过多次比较和交换来实现排序,不停的设定分界值并进行两边的排序,达到整组数组排序的效果
* 练习快速排序,前小后大
*
* 出现的问题:
* 双边指针交换法
* 1.从左向右比较时,是找大的数,并和右边小的数交换。双边指针交换法中,循环思路是如果不符合交换的条件,则对指针进行++或--,所以比较时,使用arr[leftIndex] <= pivot,右边则相反。
* 2.因为pivot是找的首元素,所以左边比较时,要注意要加上=,否则左指针循环将卡在第一个位置无法移动。
* 3.交换两数的时候,因为交换的是数组的数,数组存储的是地址而不是内容,不能用简单的a和b,需要用arr[a]、arr[b]
* 4.如代码中所示,每次比较后将当前指针数据与分界值互换的操作是必要的。应该是用来激活每次pivot所处的值的比较
* 双边指针挖坑法
* 1.挖坑指顶替、直接复制而不是交换,第一个顶掉的是pivot的值,最后再将pivot复制给最后一个空的坑
* 2.在挖坑法中,左边比较加不加=不影响程序运行结果。pivot被顶替了,不存在左边比较时一直和pivot相等而卡住的情况。
* 单边指针法
* 1.将找到的小的值跟mark++交换,因为mark原来在pivot的位置,改变后原来在已经交换过的位置,所以要++。
*/
public class quick {
public static void main(String[] args) {
int[] arr = createArr();
System.out.println("这是初始数组");
printArr(arr);
//在此处进行快速排序
quickSort(arr, 0, arr.length - 1);
System.out.println("\n这是处理后的数组");
printArr(arr);
}
//排序函数,用到递归(所以创建函数,在函数中调用函数)
public static void quickSort(int[] arr, int startIndex, int endIndex){
if(startIndex >= endIndex){return;}
// int pivotIndex = doublePointSwap(arr, startIndex, endIndex); //双边指针交换法
// int pivotIndex = doublePointHole(arr, startIndex, endIndex); //双边指针挖坑法
int pivotIndex = singlePoint(arr, startIndex, endIndex); //单边指针法
quickSort(arr, startIndex, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, endIndex);
}
/**
* 双边指针交换法
* 1.记录分界值pivot(首元素)
* 2.从左向右找比分界值大的值,从右往左找比分界值小的值
* 3.左右指针数据交换,进入下次循环
* 4.结束后将当前指针数据与pivot交换,返回pivot值下标(见quickSort函数)
*
* @return
*/
public static int doublePointSwap(int[] arr, int startIndex, int endIndex){
int pivot = arr[startIndex];
int leftIndex = startIndex;
int rightIndex = endIndex;
while (leftIndex < rightIndex){
while (arr[rightIndex] > pivot && leftIndex < rightIndex){ rightIndex--; } //从右向左
while (arr[leftIndex] <= pivot && leftIndex < rightIndex){ leftIndex++; } //从左向右
if(leftIndex < rightIndex){ swap(arr, leftIndex, rightIndex); } //两指针数据交换
}
/*
为什么要有这两句?
如果没有这两句,每次排序的pivot就都在第一位,将右指针的值和第一个位置的值交换,可以激活第一个值的比较
这里用右指针和左指针都可以,毕竟上面筛下来,到这左右指针应该相等
*/
arr[startIndex] = arr[rightIndex];
arr[rightIndex] = pivot;
return rightIndex; //返回分界值所在下标
}
/**
* 双边指针挖坑法
* 1.记录分界值pivot(首元素),创建双边指针
* 2.左右指针轮流为坑,先判断右边比分界值小的值,填入左指针的坑中,此时右指针变成坑
* 3.判断左边比分界值大的值,填入右指针的坑中,左指针变成坑
* 4.结束后将分界值放到当时的坑中,返回坑的指针位置
*
* @return
*/
public static int doublePointHole(int[] arr, int startIndex, int endIndex){
int pivot = arr[startIndex];
int leftIndex = startIndex;
int rightIndex = endIndex;
while (leftIndex < rightIndex){
while (arr[rightIndex] > pivot && leftIndex < rightIndex){ rightIndex--; }
if (leftIndex < rightIndex){
arr[leftIndex] = arr[rightIndex];
leftIndex++;
}
while (arr[leftIndex] <= pivot && leftIndex < rightIndex){ leftIndex++; }
if (leftIndex < rightIndex){
arr[rightIndex] = arr[leftIndex];
rightIndex--;
}
}
arr[rightIndex] = pivot;
return rightIndex;
}
/**
* 单边指针法
* 1.记录分界值pivot(首元素),创建左边单指针
* 2.遍历指针,如果比分界值小,则跟指针++所在的数字交换
* 3.结束后,将分界值所在位置与指针所在位置交换
*
* @return
*/
public static int singlePoint(int[] arr, int startIndex, int endIndex){
int pivot = arr[startIndex];
int mark = startIndex;
for (int i = startIndex + 1; i <= endIndex; i++) {
if(arr[i] < pivot){
mark++;
swap(arr, mark, i);
}
}
arr[startIndex] = arr[mark];
arr[mark] = pivot;
return mark;
}
//生成随机数组
public static int[] createArr(){
Random rd = new Random();
int[] arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = rd.nextInt(99) + 1;
}
return arr;
}
//打印数组
public static void printArr(int[] arr){
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
//交换内容
public static void swap(int[] arr, int a, int b){
int tank = arr[a];
arr[a] = arr[b];
arr[b] = tank;
}
}
插入排序
package com.academicdog.sorting;
import java.util.Random;
/**
* 插入排序:针对少量元素排序,将一个记录插入到已经排好序的有序表中
* 练习插入排序,前小后大
*/
public class insert {
public static void main(String[] args) {
int[] arr = createArr();
System.out.println("这是初始数组");
printArr(arr);
//这里进行插入排序
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < i; j++) {
if(arr[i] < arr[j]){
swap(arr, j, i);
}
}
}
System.out.println("\n这是处理后的数组");
printArr(arr);
}
//生成随机数组
public static int[] createArr() {
Random rd = new Random();
int[] arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = rd.nextInt(99) + 1;
}
return arr;
}
//打印数组
public static void printArr(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
//交换内容,这里发生了改变,因为插入了一个小的值,所以要先把之间的值往后移
public static void swap(int[] arr, int a, int b) {
int tank = arr[b];
for (int i = b; i > a; i--) {
arr[i] = arr[i - 1];
}
arr[a] = tank;
}
}