排序算法大全(动画模拟、清晰明了)

排序算法大全

一、冒泡排序

思路:每两个相邻的元素进行比较,直至最大(最小)的元素沉到底下,经过多轮之后这样的操作,从而使得完成排序。

特点:稳定
平均时间复杂度:O(n2)
最佳时间复杂度:O(n)
最坏时间复杂度:O(n2)
空间复杂度:O(1)

动画演示:

冒泡排序动画演示
代码如下:

public class BubbleSort {
	public static void main(String[] args) {
		int[] arr= {10,9,8,7,6,5,4,3,2,1};
		bubbleSort(arr);
		// 遍历数组
		for(int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+"  ");
		}
	}
	/**
	 * 冒泡排序
	 * @param arr 数组
	 */
	public static void bubbleSort(int[] arr) {
		int len=arr.length;
		for(int i=0;i<len-1;i++) {
			for(int j=0;j<len-i-1;j++) {
				if(arr[j]>arr[j+1]) {
					int temp=arr[j];
					arr[j]=arr[j+1];
					arr[j+1]=temp;
				}//end if
			}// end for
		}// end for
	}// end method
}

在这里插入图片描述

二、选择排序

思路:每次从位置 i 之后选择一个最小的数(升序)和 i 进行交换,经过n轮之后数组得到有序。

注意:选择排序是不稳定的排序,举个例子:数组 6、7、6、2、8,在对其进行第一遍循环的时候,会将第一个位置的6与后面的2进行交换。此时,就已经将两个6的相对前后位置改变了。因此选择排序不是稳定性排序算法。

平均时间复杂度:O(n2)
最快时间复杂度:O(n2)
最坏时间复杂度:O(n2)
空间复杂度:O(1)

动画演示:
在这里插入图片描述
代码如下:

public class SelectionSort {
	public static void main(String[] args) {
		int[] arr= {10,9,8,7,6,5,4,3,2,1};
		selectionSort(arr);
		// 遍历数组
		for(int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+"  ");
		}
	}
	
	public static void selectionSort(int[] arr) {
		int len=arr.length;
		for(int i=0;i<len-1;i++) {
			int k=i;
			for(int j=i+1;j<len;j++) {
				if(arr[k]>arr[j]) {
					k=j;
				}// end if
			}//end for
			int temp=arr[i];
			arr[i]=arr[k];
			arr[k]=temp;
		}
	}
}

三、插入排序

思路:首先找到一个最小的元素(升序)放到起始位置。然后从剩余元素中找到下一个最小的数放到已经起始位置的后面,之后继续从剩余元素中找下一个最小的数放到上一个数的后面。循环n次这样的操作,从而达到数组有序。

特点:稳定
平均时间复杂度:O(n2)
最快时间复杂度:O(n)
最坏时间复杂度:O(n2)
空间复杂度:O(1)

动画演示:
在这里插入图片描述
代码如下:

public class InsertionSort {
	public static void main(String[] args) {
		int[] arr= {10,9,8,7,6,5,4,3,2,1};
		insertionSort(arr);
		// 遍历数组
		for(int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+"  ");
		}
	}
	/**
	 * 插入排序
	 * @param arr 要排序的数组
	 */
	public static void insertionSort(int[] arr) {
		int len=arr.length;
		for(int i=0;i<len-1;i++) {
			int cur=arr[i+1];
			int pre=i;
			while(pre>=0 && cur<arr[pre]) {
				arr[pre+1]=arr[pre];
				pre--;
			}//end while
			arr[pre+1]=cur;
		}//end for
	}
}

四、希尔排序

思路:希尔排序其实是插入排序的一种改进方法,将一组数据分成了若干组,然后组内进行插入排序,然后继续细分,细分到每一个元素一组,这个时候数组已经基本有序,再进行插入排序就只需要微调数组的顺序。

特点:不稳定
平均时间复杂度:O(nlog2n)
最佳时间复杂度:O(nlog2n)
最坏时间复杂度:O(nlog2n)
空间复杂度:O(1)

动画演示:
希尔排序动画演示
代码如下:

public class ShellSort {
	public static void main(String[] args) {
		int[] arr= {10,9,8,7,6,5,4,3,2,1};
		shellSort(arr);
		// 遍历数组
		for(int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+"  ");
		}
	}
	/**
	 * 希尔排序
	 * @param arr 要排序的数组
	 */
	public static void shellSort(int[] arr) {
		int len=arr.length;
		int group=len/2;
		while(group>0) {
			for(int i=group;i<len;i++) {
				int cur=arr[i];
				int preIndex=i-group;
				while(preIndex>=0 && cur<arr[preIndex]) {
					arr[preIndex+group]=arr[preIndex];
					preIndex=preIndex-group;
				}//end while
				arr[preIndex+group]=cur;
			}//end for
			group/=2;
		}//end while
	}
}

五、归并排序

思路:把数组平均分成左右两份,然后再分别对左右两边进行平分,循环这样的操作,直至左右两边都成一个元素。最后一层一层往上归并直至完成排序。

特点:稳定
平均时间复杂度:O(nlogn)
最佳时间复杂度:O(nlogn)
最坏时间复杂度:O(nlogn)
空间复杂度:O(n)

图片演示:
归并排序图片演示
动画演示:
归并排序动画演示
代码如下:

public class MergeSort {
	public static void main(String[] args) {
		int[] arr= {10,9,8,7,6,5,4,3,2,1};
		int[] resultArr=new int[arr.length];
		resultArr=mergeSort(arr);
		// 遍历数组
		for(int i=0;i<resultArr.length;i++) {
			System.out.print(resultArr[i]+"  ");
		}
	}
	public static int[] mergeSort(int[] arr){
		if(arr.length<2)
			return arr;
		int len=arr.length;
		int mid=len/2;
		int[] left=Arrays.copyOfRange(arr, 0, mid);
		int[] right=Arrays.copyOfRange(arr, mid, len);
		int[] leftArr=mergeSort(left);
		int[] rightArr=mergeSort(right);
		return merge(leftArr,rightArr);
	}
	private static int[] merge(int[] leftArr, int[] rightArr) {
		// TODO Auto-generated method stub
		int leftLen=leftArr.length;
		int rightLen=rightArr.length;
		int[] resultArr=new int[leftLen+rightLen];
		int i=0,j=0,k=0;
		while(i<leftLen && j<rightLen) {
			if(leftArr[i] < rightArr[j]) {
				resultArr[k++]=leftArr[i];
				i++;
			}else{
				resultArr[k++]=rightArr[j];
				j++;
			}
		}
		while(i<leftLen)	resultArr[k++]=leftArr[i++];
		while(j<rightLen)	resultArr[k++]=leftArr[j++];
		return resultArr;
	}	
}

六、快速排序

思路:从序列中找一个基准值(这里令序列第一个数为基准值),定义左右两个指针,右指针从右边开始寻找第一个小于基准值的数,左指针从左边开始寻找第一个大于基准值的数,然后将左右指针对应的数进行交换,当左右两指针相遇时,把基准值和左(或右)指针进行交换,然后再将左右两边分别进行这样的操作,最终使得数组有序。

特点:不稳定
平均时间复杂度:O(nlogn)
最佳时间复杂度:O(nlogn)
最差时间复杂度:O(n2)

图片演示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码如下:

public class QuickSort {
	public static void main(String[] args) {
		int[] arr= {10,9,8,7,6,5,4,3,2,1};
		quick_sort(arr,0,arr.length-1);
		System.out.print(Arrays.toString(arr));
	}
	public static void quick_sort(int[] arr,int left,int right) {
		if(left>right)
			return;
		int baseValue=arr[left];
		int l=left;
		int r=right;
		while(l!=r) {
			// 注意:当设置最左边元素为基准值时,必须从右边开始找。
			// 因为最后i、j 停留的位置的值肯定是要 小于 基准值 的 此时交换索引 j 和最左边元素(基准值) 符合将小于基准值的值放到基准值的左边这一条件
			while(arr[r]>=baseValue && l<r) r--;  // 找到第一个小于基准值的
			while(arr[l]<=baseValue && l<r) l++;  // 找到第一个大于基准值的
			
			if(l<r) {
				int temp=arr[l];
				arr[l]=arr[r];
				arr[r]=temp;
			}
		}
		
		arr[left]=arr[l];
		arr[l]=baseValue;
		quick_sort(arr,left,l-1);
		quick_sort(arr,l+1,right);
	}
}

七、堆排序

思路:首先将数组建立成大顶堆,然后将大顶堆的第一个元素和最后一个元素交换,最后一个元素就固定了,不再参与排序。继续调整堆,使得堆再一次变成大顶堆,将这一次大顶堆的第一个元素和这一次大顶堆的最后一个元素交换。通过这样循环n次达成数组有序。

特点:不稳定
平均时间复杂度:O(nlogn)
最佳时间复杂度:O(nlogn)
最坏时间复杂度:O(nlogn)

动画演示:
堆排序动画演示
代码如下:

public class HeapSort {
	public static void main(String[] args) {
		int[] arr= {10,9,8,7,6,5,4,3,2,1};
		heapSort(arr);
		// 遍历数组
		for(int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+"  ");
		}
		
	}
	public static void heapSort(int[] arr) {
		int len=arr.length;
		int n=len;
		buildHeap(arr);
		for(int i=0;i<len;i++) {
			//交换
			swap(arr, 0, n-1);
			n--;
			adjustHeap(arr, 0, n);
		}
		
	}
	/**
	 * 建立大顶堆
	 * @param arr 数组
	 */
	private static void buildHeap(int[] arr) {
		int len=arr.length;
		for(int i=len/2-1;i>=0;i--) {
			adjustHeap(arr,i,len);
		}//end for
		
	}
	/**
	 * 调整堆
	 * @param arr 数组
	 * @param i 位置i
	 * @param len 数组未排序的元素长度
	 */
	private static void adjustHeap(int[] arr, int i,int len) {
		int maxIndex=i;
		if(2*i+1 < len && arr[2*i+1]>arr[maxIndex]) {
			maxIndex=2*i+1;
		}//end if
		if(2*i+2 < len && arr[2*i+2]>arr[maxIndex]) {
			maxIndex=2*i+2;
		}
		//交换
		if(i!=maxIndex) {
			swap(arr,i,maxIndex);
			adjustHeap(arr,maxIndex,len);
		}
	}
	
	/**
	 * 交换位置
	 * @param arr 数组
	 * @param i 位置i
	 * @param maxIndex 位置maxIndex
 	 */
	private static void swap(int[] arr, int i, int maxIndex) {
		int temp=arr[i];
		arr[i]=arr[maxIndex];
		arr[maxIndex]=temp;
	}
}

八、计数排序

思路:将数组A中的元素作为一个索引存入另一个数组B中,最后遍历数组B,输出数组B元素不为0的索引。

特点:稳定
平均时间复杂度:O(n+k)
最佳时间复杂度:O(n+k)
最坏时间复杂度:O(n+k)

动画演示:
计数排序动画演示
代码如下:

public class CountingSort {
	public static void main(String[] args) {
		int[] arr= {10,9,8,7,6,5,4,3,2,1};
		countingSort(arr);
	}
	/**
	 * 计数排序
	 * @param arr 数组
	 */
	private static void countingSort(int[] arr) {
		int len=arr.length;
		int max=arr[0],min=arr[0];
		for(int i=1;i<len;i++) {
			if(max<arr[i]) {
				max=arr[i];
			}//end if
			if(min>arr[i]) {
				min=arr[i];
			}//end if
		}//end for
		
		int[] bucket=new int[max-min+1];
		Arrays.fill(bucket, 0);
		for(int i=0;i<len;i++) {
			bucket[arr[i]-min]++;
		}
		for(int i=0;i<max-min+1;) {
			if(bucket[i]!=0) {
				System.out.print(i+min+"  ");
				bucket[i]--;
			}else {
				i++;
			}
		}
	}
	
}

九、桶排序

内容后期更新

十、基数排序

内容后期更新

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值