介绍
今天在刷LeetCode时需要写一个排序算法,结果憋了半天没写出来,想想有好久没有写排序算法了,就来系统地再回顾一遍,以前一直是白嫖别人的博客,这次自己写一个,方便他人也帮助自己加深记忆吧。
一共介绍十种算法,分为两个博客。
(如果有错,恳请各位大佬指出 orz)
准备
本次代码实现为java,网上有很多用java的实现,但是没有用到面向对象的特性,每次交换两个数据都要花三行代码,不方便阅读,我将数组进行了一次封装,方便后面算法实现的使用,个人认为是很有必要的。
public class SortArray {
private int[] arr;
private int len;
//构造函数,生成随机数组
SortArray(int len,int max){
this.len = len;
this.arr = new int[len];
for (int i = 0; i < len; i++) {
this.arr[i] = (int) (Math.random() * max);
}
}
//长度get方法
public int getLen() {
return len;
}
// 数组get方法
public int[] getArr() {
return arr;
}
//交换数组内两个元素
public void swap(int m, int n){
int temp = this.arr[m];
this.arr[m] = this.arr[n];
this.arr[n] = temp;
}
// 指定位置元素赋值
public void changeValue(int index,int value){
this.arr[index] = value;
}
//获得指定位置元素
public int getNum(int index){
return this.arr[index];
}
}
在后面的算法代码中,就可以直接使用这个类了
public static void main(String[] args){
SortArray arr = new SortArray(48,100); // 随机生成48个0-100的数测试
System.out.println(Arrays.toString(arr.getArr())); // 输出生成数组
// 执行排序算法
System.out.println(Arrays.toString(arr.getArr())); //查看排序后数组
}
准备完成,下面正式开始讨论排序算法:
选择排序
算法思想:作为最基本的排序算法,选择排序应该是每个人第一个学习的排序算法了。算法思想也很简单,双重循环,每次找出最大或者最小的元素,并且将其放在对应的位置。
时间复杂度分析:用到了双重循环,很容易求得T(n) = O(n2)
// 选择排序
public static void SelectionSort(SortArray arr){
for (int i = 0; i < arr.getLen(); i++) {
int min = 101; //由于数组是0-100范围,初始min取为101即可
int index = 0; // index记录最小元素的位置
// 内循环找出最小的元素
for (int j = i; j < arr.getLen(); j++) {
if (arr.getNum(j) < min) {
index = j;
min = arr.getNum(j);
}
}
arr.swap(i,index); //交换元素
}
}
冒泡排序
算法思想:从头到尾两两比较,将最大或者最小的元素移到(冒泡到)数组的末尾
时间复杂度:还是用到了双重循环,T(n) = O(n2)
// 冒泡排序
public static void BubbleSort(SortArray arr){
for (int i = 0; i < arr.getLen()-1; i++) {
for (int j = 0; j < arr.getLen()-i-1; j++) {
// 两两比较
if(arr.getNum(j)>arr.getNum(j+1))
arr.swap(j,j+1);
}
}
}
插入排序
算法思想:将数组分为有序和无序两个部分,前面为有序,遍历无序部分,依次往有序部分进行插入,直到整个数组都有序。
时间复杂度:两重循环,T(n) = O(n2)
// 插入排序
public static void InsectionSort(SortArray arr){
for (int i = 1; i < arr.getLen(); i++) {
int temp = arr.getNum(i);
for (int j = i-1; j >=0; j--) {
// 如果不符合次序就把元素往后移
if(temp < arr.getNum(j)){
arr.swap(j+1,j);
}
// 符合次序,直接插入,跳出循环
else{
arr.changeValue(j+1,temp);
break;
}
}
}
}
希尔排序
算法思想:希尔排序,顾名思义就是由希尔(shell)提出的排序算法,也叫缩减增量排序,实际上是一种改进的插入排序算法,相比插入排序,希尔排序增加了一个for循环,但是使得排序的效率有所提升,使用更少的移动次数就可达到更好的效果。
时间复杂度:希尔排序的时间复杂度与增量序列的选择关系很大,一般使用的希尔增量并不是最佳的选择,但是总的来说,T(n) 在O(nlog2n)与O(n2)之间,优于以上几种排序算法。
public static void ShellSort(SortArray arr){
for(int step = arr.getLen()/2 ; step > 0 ; step /= 2){
// 对每一个元素进行组内插入排序
for (int i = step; i < arr.getLen(); i++) {
int temp = arr.getNum(i);
for (int j = i-step; j >= 0 ; j -= step) {
if(temp < arr.getNum(j)){
arr.swap(j+step,j);
}
else{
arr.changeValue(j+step,temp);
break;
}
}
}
}
}
快速排序
算法思想:排序算法的一个坎(也许是我菜)。算法思想是选出一个基准,循环后时基准前面的数都比基准小,后面的数都比基准大,然后递归地对基准前面的数和基准后面的数进行排序。
时间复杂度:由于用到了递归,加上算法本身很巧妙,T(n) = O(nlogn)
//快速排序
public static void QuickSort(SortArray arr,int low,int high){
if(low >= high) return;
int i=low-1,j=high+1;
int flag = arr.getNum((low+high)/2);
while(i<j){
do i++; while(arr.getNum(i)<flag);
do j--; while(arr.getNum(j)>flag);
if( i < j ) arr.swap(i,j);
}
// 递归左右两个部分
QuickSort(arr,low,j);
QuickSort(arr,j+1,high);
}