本文涵盖的排序:
1. 快速排序
2. 归并排序
3. 冒泡排序
4. 插入排序
5. 选择排序
6. 希尔排序
7. 堆排序
8. 计数排序
一个类一个排序,在一个统一的Main类中测试运行
测试用例在注释里直接复制
堆排序我没完全弄懂,所以引用了其他博客里面的
如果有错误请在评论区带测试用例留言
不然我也找不出来是哪出错
备注:想偷懒直接使用其中一种排序的朋友,不必继承父类,但是记得把父类的swap方法复制进去
先是排序类的父类:
public abstract class Sort {
public abstract void sort(int[] array);
static void swap(int[] array, int i, int j) {
// 该方法用于交换数组第i项和第j项
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
然后是排序部分(继承父类)
快速排序
public class quickSort extends Sort{
@Override
public void sort(int[] array) {
quickSort(array, 0, array.length-1);
}
private void quickSort(int[] array, int le, int ri){
if (le >= ri){
return;
}
int key = array[le];
int low = le;
int hi = ri;
while(low < hi){
while (low < hi && array[hi] >= key){
hi--;
}
while (low < hi && array[low] <= key){
low++;
}
if (low < hi){
swap(array, low, hi);
}
}
// low == hi
swap(array, low, le);
quickSort(array, le, low-1);
quickSort(array, low+1, ri);
}
}
归并排序
public class mergeSort extends Sort{
@Override
public void sort(int[] array) {
int[] temp = new int[array.length];
// temp用于临时存取数据
mergeSort(array, 0, array.length - 1, temp);
}
private void mergeSort(int[] array, int low, int hi, int[] temp){
if (low >= hi){
return;
}
int middle = (low + hi)/2;
mergeSort(array, middle + 1, hi, temp);
mergeSort(array, low, middle, temp);
merge(array, low, middle, hi, temp);
}
private void merge(int[] array, int low, int middle, int hi, int[] temp) {
// 运行merge方法时,数组分为两部分
// 一部分是low~middle(暂时称呼为左数组)
// 另一部分是middle+1~hi(暂时称呼为右数组)
int right_start = middle + 1;
// 右数组第一位,right_start从middle+1到hi
int left_start = low;
// 左数组第一位,left_start从low到middle
int index_for_temp = low;
// temp用于储存结果,所以temp的index是从low到hi
// 逐个归并
while(left_start <= middle && right_start <= hi) {
// 遍历左右数组
if (array[left_start] <= array[right_start])
// 左数组left_start位置上的值比右数组right_start值小
temp[index_for_temp++] = array[left_start++];
else
// 左数组left_start位置上的值比右数组right_start值大
temp[index_for_temp++] = array[right_start++];
}
// 由于左右数组大小不一定相同,此时左右数组可能有一个还没有遍历结束
// 将左边剩余的归并
while (left_start <= middle) {
temp[index_for_temp++] = array[left_start++];
}
// 将右边剩余的归并
while ( right_start <= hi ) {
temp[index_for_temp++] = array[right_start++];
}
// 将此次temp的改变放到array中
for (int i = low; i <= hi; i++) {
array[i] = temp[i];
}
}
}
冒泡排序
public class bubbleSort extends Sort{
@Override
public void sort(int[] array) {
boolean swaped = true;
// 判断是否进行过交换操作
// 是用于稍稍增加效率的办法,可以不用
for (int i = 0; i < array.length-1; i++) {
swaped = false;
for (int j = 0; j < array.length-1; j++) {
if (array[j] > array[j+1]){
swap(array, j, j+1);
swaped = true;
}
}
if (!swaped){
//若该次便利未经过交换,则表示数组已经是从小到大的顺序了,可以退出循环
break;
}
}
}
}
插入排序
public class insertionSort extends Sort{
@Override
public void sort(int[] array) {
for (int i = 1; i < array.length; i++) {
// 从第二位开始插入
int temp = array[i];
int j = i;
while (j > 0 && temp < array[j-1]){
// 要插入的数比它前面的数小,该数往前挪(前面一位数占据该数当前的位置)
array[j] = array[j-1];
j--;
}
if (j != i){
// 该数确实比它前面的数字小,且向前挪动了,该数可以插入了
array[j] = temp;
}
}
}
}
选择排序
public class selectionSort extends Sort{
@Override
public void sort(int[] array) {
int minIndex;
for (int i = 0; i < array.length; i++) {
minIndex = i;
for (int j = i+1; j < array.length; j++) {
if (array[i] > array[j]){
minIndex = j;
}
}
if (minIndex != i){
// 最小值不是当前第i位
swap(array, i, minIndex);
// 将该位与最小位交换
}
}
}
}
希尔排序
public class shellSort extends Sort{
@Override
public void sort(int[] array) {
int gap = array.length/2;
// 将array分成gap组,同一组相邻的两个数间隔距离为gap
while (gap > 0){
for (int i = gap; i < array.length; i++) {
int j = i;
while (j - gap >= 0 && array[j] < array[j-gap]){
// array[j]和array[j-gap]是同一组相邻的两个数
// 对同一组进行排序
swap(array, j, j-gap);
j -= gap;
// 由于第j位比j-gap位小,所以将第j位换到了j-gap位
// 但是换到了j-gap位的数没有参与前面的比较,所以要比较j-gap和j-gap-gap
// 所以令j = j-gap并循环执行
}
}
gap /= 2;
}
}
}
堆排序(这个我还没完全弄懂所以先搜集了一个别人的可行的代码)
public class heapSort extends Sort{
/***
* 堆排序部分为转载内容
* 原文:https://blog.csdn.net/m0_46975599/article/details/112125116
*/
@Override
public void sort(int[] array) {
//1.构建大顶堆
for (int i = array.length/2-1; i >= 0; i--) {
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(array, i, array.length);
}
//然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。
//2.调整堆结构+交换堆顶元素与末尾元素
for (int j = array.length - 1; j > 0; j--) {
swap(array, 0, j);//将堆顶元素与末尾元素进行交换
adjustHeap(array, 0, j);//重新对堆进行调整
}
}
/**
* 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上, 也就是说只调用一次,并没有得到大顶堆)
* 就是将arr[i] 的值放到本次 调整过程中适当的位置。
* @param arr : 数组
* @param i : 非叶子节点的索引
* @param length : 对多少个元素进行调整,这个length是逐渐减少的..
*/
public void adjustHeap(int[] arr, int i, int length) {
int temp = arr[i];//先取出当前元素i
for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {//从i结点的左子结点开始,也就是2*i+1处开始
if (k + 1 < length && arr[k] < arr[k + 1]) {//如果左子结点小于右子结点,k指向右子结点
k++;
}
if (arr[k] > temp) {//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
arr[i] = arr[k];//把较大的值,赋给当前节点
i = k;//i 指向k,继续循环比较
} else {
break;
}
}
arr[i] = temp;//将temp值放到最终的位置
}
}
计数排序
public class countSort extends Sort{
@Override
public void sort(int[] array) {
int maxValue = array[0];
int minValue = array[0];
for (int i : array) {
maxValue = Math.max(i, maxValue);
minValue = Math.min(i, minValue);
}
int[] temp = new int[maxValue - minValue + 1];
// temp用于储存最大最小值之间的数出现的次数
// temp[0]是minValue出现的次数
for (int i :
array) {
temp[i-minValue]++;
}
int index = 0;
for (int i = 0; i < temp.length; i++) {
// 遍历temp
for (int j = 0; j < temp[i]; j++) {
// temp[i]每有一位,便向array中放入一次数字
array[index] = i+minValue;
index++;
}
}
}
}
最后是测试用的Main类
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
/**
* 测试数据
* 1 5 9 6 8 3 5 4 6 2 7 5 9 6
* 99 66 66 55 88 22 55 55 55 66 9 4 3 55 16 84 91 77
* 3
* 5 8 3
*/
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Sort sort = null;
while (true) {
System.out.println("请输入待测试算法");
System.out.println("1. 快速排序");
System.out.println("2. 归并排序");
System.out.println("3. 冒泡排序");
System.out.println("4. 插入排序");
System.out.println("5. 选择排序");
System.out.println("6. 希尔排序");
System.out.println("7. 堆排序");
System.out.println("8. 计数排序");
switch (br.readLine()) {
// 好像自Java7之后switch就可以直接用String了,
// 版本不兼容的话这里也可以用Integer.parseInt()转换成int类型
// 如果想无限排序,自己在外面再套一个循环
case "1":
sort = new quickSort();
break;
case "2":
sort = new mergeSort();
break;
case "3":
sort = new bubbleSort();
break;
case "4":
sort = new insertionSort();
break;
case "5":
sort = new selectionSort();
break;
case "6":
sort = new shellSort();
break;
case "7":
sort = new heapSort();
break;
case "8":
sort = new countSort();
break;
default:
System.out.println("请从列表中选出序号!");
continue;
}
break;
}
System.out.println("请输入测试用例:");
String[] s = br.readLine().split(" ");
int[] array = new int[s.length];
for (int i = 0; i < s.length; i++) {
array[i] = Integer.parseInt(s[i]);
}
sort.sort(array);
for (int j : array) {
System.out.print(j + " ");
}
}
}