一.冒泡算法
冒泡排序(Bubble Sort)是一种简单的排序算法,因其基本操作过程中较小的元素逐渐“浮”到数组前端而得名。下面是冒泡排序的详细说明:
基本原理
比较相邻元素:算法重复地遍历待排序的数列,一次比较两个元素,如果它们的顺序(如从小到大或从大到小)错误就把它们交换过来。
重复遍历:每次遍历都会使未排序的部分中最大(或最小)的元素“冒泡”到数列的一端。
减少检查次数:每一轮遍历后,由于最大的元素已经“冒泡”到了正确的位置,下一轮遍历时可以略过数组的末尾部分,减少不必要的比较。
终止条件:当整个数列变成有序时,算法结束。
特点
时间复杂度:平均和最坏情况下时间复杂度均为O(n^2),其中n是数组长度。最好情况下(即数组已经是排序状态)时间复杂度为O(n)。
空间复杂度:O(1),因为它是原地排序,不需要额外的存储空间。
稳定性:冒泡排序是稳定的排序算法,即相等的元素的相对顺序不会改变。
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int[]arr=new int[10];
for (int i = 0; i <arr.length ; i++) {
arr[i]=(int)(Math.random()*100+1);
}
System.out.println(Arrays.toString(arr));
System.out.println("------------------------");
//升序:
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]) {
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
System.out.println(Arrays.toString(arr));
}
System.out.println();
}
System.out.println("----------------------");
//降序:
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length-1-i; j++) {
if (arr[j]<arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
System.out.println(Arrays.toString(arr));
}
System.out.println();
}
}
对冒泡排序所用时间以及排序中交换次数的比较的输出
import java.util.Arrays;
import java.util.Random;
public class BubbleSort2 {
public static void main(String[] args) {
/*
int[]arr=new int[10];
for (int i = 0; i <arr.length ; i++) {
arr[i]=(int)(Math.random()*100+1);
}
System.out.println(Arrays.toString(arr));
System.out.println("------------------------");
*/
Random random=new Random();
int numberbound=100;
int numbercount=50;
int[]arr=new int[numbercount];
for (int i = 0; i < arr.length; i++) {
arr[i]=random.nextInt(numberbound);
}
System.out.println(Arrays.toString(arr));
//比较次数:
int compareCount=0;
//交换次数:
int swapCount =0;
//循环开始时间
long startTime=System.currentTimeMillis();
for (int i = 0; i < arr.length-1 ; i++) {
for (int j = 0; j < arr.length-1-i ; j++) {
compareCount++;
if (arr[j]>arr[j+1]) {
swapCount++;
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
System.out.println(Arrays.toString(arr));
}
System.out.println();
}
//循环结束时间:
long endTime=System.currentTimeMillis();
System.out.println("循环运行时间为"+(endTime-startTime));
System.out.println("循环比较次数为"+compareCount);
System.out.println("循环交换次数为"+swapCount);
}
}
二.插入排序
插入排序(Insertion Sort)是一种简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。以下是插入排序的详细步骤和示例代码。
基本步骤
从第一个元素开始,该元素可以认为已经被排序。
取出下一个元素,在已经排序的元素序列中从后向前扫描。
比较:如果该元素(已排序)大于新元素,将该元素移到下一位置。
重复步骤3,直到找到已排序的元素小于或等于新元素的位置。
将新元素插入到该位置。
重复步骤2~5。
特点
时间复杂度:平均和最坏情况下时间复杂度均为O(n^2),其中n是数组长度。最好情况下(即数组已经是排序状态)时间复杂度为O(n)。
空间复杂度:O(1),因为它是在原地进行排序,不需要额外的存储空间。
稳定性:插入排序是稳定的排序算法,即相等的元素的相对顺序不会改变。
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
public class InsertionSort {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
Random random=new Random();
System.out.println("请输入数组长度:");
int length=scan.nextInt();
System.out.println("请输入数组取值范围");
int bound= scan.nextInt();
int[]arr=new int[length];
for (int i = 0; i < arr.length; i++) {
arr[i]= random.nextInt(bound);
}
System.out.println("原数组为"+ Arrays.toString(arr));
//升序:
for (int i = 1; i < arr.length ; i++) {
int j= i;
while (j>0){
if(arr[j]<arr[j-1]){
int temp=arr[j];
arr[j]=arr[j-1];
arr[j-1]=temp;
j--;
}else {
break;
}
System.out.println(Arrays.toString(arr));
}
System.out.println();
}
System.out.println("升序后的数组为"+Arrays.toString(arr));
//降序:
for (int i = 1; i < arr.length ; i++) {
int j= i;
while (j>0){
if(arr[j]>arr[j-1]){
int temp=arr[j];
arr[j]=arr[j-1];
arr[j-1]=temp;
j--;
}else {
break;
}
System.out.println(Arrays.toString(arr));
}
System.out.println();
}
System.out.println("降序后的数组为"+Arrays.toString(arr));
}
}
三.归并排序
归并排序(Merge Sort)是一种分而治之的算法,其核心思想是将数组分成两半分别排序,然后将排序好的两部分合并在一起。下面是归并排序的详细步骤和示例代码。
基本步骤
分解:将当前区间一分为二,即求中点。
递归排序:递归地对两个子区间a[low...mid]和a[mid+1...high]进行归并排序。
合并:将已排序的两个子区间合并成一个有序区间。
特点
时间复杂度:无论最好、最坏还是平均情况,时间复杂度均为O(n log n),其中n是数组长度。
空间复杂度:需要O(n)的辅助空间来存放临时数组用于合并过程。
稳定性:归并排序是稳定的排序算法,即相等的元素的相对顺序不会改变。
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) {
int[]arr=new int[8];
for (int i = 0; i <arr.length ; i++) {
arr[i]=(int)(Math.random()*100+1);
}
System.out.println(Arrays.toString(arr));
System.out.println("------------------------");
int[]arr1=mergeSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr1));
int[]arr2=mergeSort1(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr2));
}
//升序
public static int[] mergeSort(int[]array,int start,int end){
if(start==end){
return new int[]{array[start]};
}
int mid=start+(end-start)/2;
int []leftArray=mergeSort(array, start, mid);
int []rightArray=mergeSort(array, mid+1, end);
int []newArray=new int[leftArray.length+rightArray.length];
int l=0,r=0,n=0;
while (l<leftArray.length &&r<rightArray.length){
newArray[n++]=leftArray[l]<=rightArray[r]?leftArray[l++]:rightArray[r++];
}
while (l<leftArray.length){
newArray[n++]=leftArray[l++];
}
while (r<rightArray.length){
newArray[n++]=rightArray[r++];
}
return newArray;
}
//降序
public static int[] mergeSort1(int[]array,int start,int end){
if(start==end){
return new int[]{array[start]};
}
int mid=start+(end-start)/2;
int []leftArray=mergeSort1(array, start, mid);
int []rightArray=mergeSort1(array, mid+1, end);
int []newArray=new int[leftArray.length+rightArray.length];
int l=0,r=0,n=0;
while (l<leftArray.length &&r<rightArray.length){
newArray[n++]=leftArray[l]>=rightArray[r]?leftArray[l++]:rightArray[r++];
}
while (l<leftArray.length){
newArray[n++]=leftArray[l++];
}
while (r<rightArray.length){
newArray[n++]=rightArray[r++];
}
return newArray;
四.快速排序
快速排序(Quick Sort)是一种高效的排序算法,采用分治法策略,其基本思想是选择一个基准元素,通过一趟排序将待排序的记录分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。以下是快速排序的详细步骤和示例代码。
基本步骤
选择基准:从数列中挑出一个元素,称为“基准”(pivot)。
分区操作:重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
递归排序:递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
特点
时间复杂度:平均情况下时间复杂度为O(n log n),最坏情况下(数组已经是正序或逆序)为O(n^2),但可以通过随机选取基准元素来优化,使得最坏情况概率极低。
空间复杂度:O(log n),主要来自于递归调用栈的深度。
稳定性:快速排序不是稳定的排序算法,因为相等的元素可能会因为分区操作而改变原有的相对顺序。
import java.util.Arrays;
public class QuickSort {
public static void main(String[] args) {
int[]arr=new int[10];
for (int i = 0; i <arr.length ; i++) {
arr[i]=(int)(Math.random()*100+1);
}
System.out.println(Arrays.toString(arr));
System.out.println("------------------------");
QuickSort(arr,0, arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static void QuickSort(int[]array,int start,int end){
int pivot=array[end];
int x=start-1;
for (int i = start; i <end ; i++) {
if(array[i]<pivot){
if(i-x>1){
int temp=array[i];
array[i]=array[x+1];
array[x+1]=temp;
x++;
}else {
x=i;
}
}
}
if(pivot<array[x+1]){
array[end]=array[x+1];
array[x+1]=pivot;
}
if (x>start){
QuickSort(array, start, x);
}
if(end-x-1>1){
QuickSort(array, x+2, end);
}
}
}
五.希尔排序
希尔排序(Shell Sort)是插入排序的一种高效改进版本,由D.L. Shell于1959年提出。其核心在于将原始数据集合分成多个子序列,每个子序列进行插入排序,随着排序的进行,子序列的数量逐渐减少,直到最后整个数据集合变为一个子序列并完成排序。这种排序算法通过比较相距一定间隔的元素,间隔逐步减小,直至为1,来达到提高效率的目的。以下是希尔排序的基本步骤和特点:
基本步骤
选择增量序列:首先选择一个增量序列,初始增量较大,然后逐渐减小增量。
分组排序:将原始数据集合分成若干子序列,每个子序列包含相隔某个增量的元素,对每个子序列应用直接插入排序。
减小增量:按照预设的规则减小增量,重复步骤2,直到增量为1,此时进行最后一次直接插入排序。
特点
时间复杂度:最好的时间复杂度情况下可以达到O(n log^2 n),但最坏情况下仍可能是O(n^2),实际性能依赖于增量序列的选择。
空间复杂度:O(1),因为希尔排序是原地排序算法。
稳定性:希尔排序不是稳定的排序算法,因为在不同的子序列中插入排序可能破坏相等元素的原有顺序。
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
public class ShellSort {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
Random random=new Random();
System.out.println("请输入数组长度:");
int length= scan.nextInt();
System.out.println("请输入数组取值范围:");
int bound=scan.nextInt();
int[]arr=new int[length];
for (int i = 0; i < arr.length; i++) {
arr[i]= random.nextInt(bound);
}
System.out.println("原数组为"+ Arrays.toString(arr));
//升序:
for (int gap = arr.length/2; gap >0 ; gap/=2) {
for (int i = gap; i < arr.length ; i++) {
for (int j = i-gap; j >=0 ; j-=gap) {
if(arr[j]>arr[j+gap]){
int temp=arr[j];
arr[j]=arr[j+gap];
arr[j+gap]=temp;
}else {
break;
}
System.out.println(Arrays.toString(arr));
}
System.out.println();
}
}
System.out.println("升序后的数组为"+Arrays.toString(arr));
//降序:
for (int gap = arr.length/2; gap >0 ; gap/=2) {
for (int i = gap; i < arr.length ; i++) {
for (int j = i-gap; j >=0 ; j-=gap) {
if(arr[j]<arr[j+gap]){
int temp=arr[j];
arr[j]=arr[j+gap];
arr[j+gap]=temp;
}else {
break;
}
System.out.println(Arrays.toString(arr));
}
System.out.println();
}
}
System.out.println("降序后的数组为"+Arrays.toString(arr));
}
}