IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 十大排序算法汇总 -> 正文阅读

[数据结构与算法]十大排序算法汇总

目录

1、冒泡排序

2、选择排序

3、插入排序

4、希尔排序

5、归并排序

6、快速排序

7、堆排序

8、计数排序

9、桶排序

10、基数排序


1、冒泡排序

思想:每次左右两两比较,把最大或最小元素放到最后,直到整体有序

时间复杂度:O(n2)

稳定性:稳定

package com.xch2.DiGui;

import java.util.*;

public class Main7_1 {

	//冒泡排序
	//小到大排序
	public static void f8(int[] arr) {
		boolean flag=true;
		int mid;
		for (int i = arr.length-1; i > 0; i--) {
			for (int j = 0; j < i; j++) {
				if(arr[j]>arr[j+1]) {
					mid=arr[j];
					arr[j]=arr[j+1];
					arr[j+1]=mid;
					flag=false;
				}
			}
			//优化,提前整体有序
			if(flag) {
				return;
			}
			flag=true;
		}
	}

	//大到小排序
	public static void f9(int[] arr) {
		boolean flag=true;
		int mid;
		for (int i = arr.length-1; i > 0; i--) {
			for (int j = 0; j < i; j++) {
				if(arr[j]<arr[j+1]) {
					mid=arr[j];
					arr[j]=arr[j+1];
					arr[j+1]=mid;
					flag=false;
				}
			}
			//优化,提前整体有序
			if(flag) {
				return;
			}
			flag=true;
		}
	}
	
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		int[] arr= {5,2,8,9,2,6,7,10};
//		f8(arr);
		f9(arr);
		System.out.println(Arrays.toString(arr));
		
	}

}

2、选择排序

思想:每次从待排数组中取一个最小或最大的元素放到前面,直到整体有序

时间复杂度:O(n2)

稳定性:不稳定

package com.xch2.DiGui;

import java.util.*;

public class Main7_1 {
	
	//选择排序(简单选择排序)
	//小到大排序
	public static void f6(int[] arr) {
		int min=arr[0],p=0,mid;
		for (int i = 0; i < arr.length-1; i++) {
			for (int j = i+1; j < arr.length; j++) {
				if(arr[j]<min) {
					p=j;
					min=arr[j];
				}
			}
			mid=arr[p];
			arr[p]=arr[i];
			arr[i]=mid;
			
			min=arr[i+1];
			p=i+1;
		}
	}
	
	//大到小排序
	public static void f7(int[] arr) {
		int max=arr[0],p=0,mid;
		for (int i = 0; i < arr.length-1; i++) {
			for (int j = i+1; j < arr.length; j++) {
				if(arr[j]>max) {
					p=j;
					max=arr[j];
				}
			}
			mid=arr[p];
			arr[p]=arr[i];
			arr[i]=mid;
			
			max=arr[i+1];
			p=i+1;
		}
	}
	
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		int[] arr= {5,2,8,9,2,6,7,10};
//		f6(arr);
		f7(arr);
		System.out.println(Arrays.toString(arr));
		
	}

}

3、插入排序

思想:每次取一个元素拆入到已排序的数组中有序的位置,直到整体有序

时间复杂度:O(n2)

稳定性:稳定

package com.xch2.DiGui;

import java.util.*;

public class Main1 {

	//插入排序
	static void f8(int[] arr,int k) {//k代表个数或数组长度
		if(k==1)//k代表元素个数
			return;
		f8(arr,k-1);//先把前k-1个元素排好序
		int index=k-1;//index代表数组下标
		while(index>0&&arr[index]<arr[index-1]) {
			int mid=arr[index];
			arr[index]=arr[index-1];
			arr[index-1]=mid;
			index--;
		}
	}
	
	//方法二(前往后排序)
	static void f9(int[] arr,int index) {//index代表开始下标,为0
		if(index==arr.length)
			return;
		int r=index;
		while(r>0&&arr[r]<arr[r-1]) {
			int mid=arr[r];
			arr[r]=arr[r-1];
			arr[r-1]=mid;
			r--;
		}
		f9(arr,index+1);//把剩余的index+1下标元素排序
	}
	
	//方法三(后往前排序)
	static void f10(int[] arr,int index) {//index代表结束下标,为arr.length-1
		if(index==-1)
			return;
		int r=index;
		while(r<arr.length-1&&arr[r]>arr[r+1]) {
			int mid=arr[r];
			arr[r]=arr[r+1];
			arr[r+1]=mid;
			r++;
		}
		f10(arr,index-1);//把剩余的index-1下标元素排序
	}
	
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		int[] arr1=new int[]{2,5,99,5,1,-5,-9};
		f8(arr1,7);
		for (int i = 0; i < arr1.length; i++) {
			System.out.print(arr1[i]+",");
		}
		System.out.println();
		
		int[] arr2=new int[]{2,5,99,5,1,-5,-9};
		f9(arr2,0);
		for (int i = 0; i < arr2.length; i++) {
			System.out.print(arr2[i]+",");
		}
		System.out.println();
		
		int[] arr3=new int[]{2,5,99,5,1,-5,-9};
		f10(arr3,6);
		for (int i = 0; i < arr3.length; i++) {
			System.out.print(arr3[i]+",");
		}
		System.out.println();
		
	}

}

4、希尔排序

思想:确定一个渐进缩小的增量,进行分组后在组内插入排序,直到整体有序(插入排序的进阶版)

时间复杂度:O(nlogn)

稳定性:不稳定

package com.xch2.DiGui;

import java.util.*;

public class Main2 {

	//希尔排序(缩小增量排序,优化插入排序)
	static void f2(int arr[]) {
		for (int incre = arr.length/2; incre > 0; incre=incre/2) {
			for (int i = incre; i < arr.length; i++) {
				int target=i;
				while(target>=incre&&arr[target]<arr[target-incre]) {
					int mid=arr[target];
					arr[target]=arr[target-incre];
					arr[target-incre]=mid;
					target-=incre;
				}
			}
		}
	}
	
	public static void main(String[] args) {
		// TODO 自动生成的方法存根=
		int arr1[]=new int[] {9,8,7,6,5,4,3,6,2,1,99,0,-4};
		f2(arr1);
		for (int i : arr1) {
			System.out.print(i+",");
		}
		System.out.println();
		
	}

}

5、归并排序

思想:分治思想,把待排数组渐进分割,进行有序合并,直到整体有序(偏合并)

时间复杂度:O(nlogn)

稳定性:稳定

package com.xch2.DiGui;

public class Main5 {

	//归并排序
	static int[] arr1;
	static void f1(int[] arr,int l,int r) {
		arr1=new int[arr.length];//外移到递归函数外,不会多次new节省存储空间
		f2(arr,l,r);
	}
	static void f2(int[]arr,int l,int r) {
		if(l>=r)//递归出口
			return;
		
		int mid=l+((r-l)>>1),left=l,right=mid+1,ori=l;
		f2(arr,l,mid);//子递归
		f2(arr,mid+1,r);
		
		for (int i = 0; i < arr1.length; i++) {
			arr1[i]=arr[i];//更新辅助数组
		}
		while(left<=mid&&right<=r) {//递归体
			if(arr1[left]<=arr1[right]) {
				arr[ori]=arr1[left];
				left++;
			}else {
				arr[ori]=arr1[right];
				right++;
			}
			ori++;
		}
		while(left<=mid) {
			arr[ori]=arr1[left];
			left++;
			ori++;
		}
	}
	
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		int[] arr=new int[] {11,8,3,4,9,8,22,0,5,8,3};
		f1(arr,0,10);
		for (int i : arr) {
			System.out.print(i+" ");
		}
		System.out.println();
		
	}

}

6、快速排序

思想:分治思想,先定主元把数组分为两(三)段[小于(等于)大于],后调整主元位置,递归渐进分割比较,直到整体有序(偏拆分)

时间复杂度:O(nlogn)

稳定性:不稳定

其中,实现方法分为三种:

1、双指针-单向扫描快速排序

2、双指针-双向扫描快速排序

3、三指针-双向扫描快速排序(相等元素优化)

定主元的两种方法:

1、取第一个

2、三点中值法(推荐,取本段数组头中尾三个元素比较值)

package com.xch2.DiGui;

public class Main4 {

	//单向单指针扫描分区快排法
	static void f1(int[] arr,int l,int r) {
		if(l>=r)//递归出口
			return;
		
		int left=l+1,right=r,mid=0;
		while(left<=right) {//递归体
			if(arr[left]<=arr[l])
				left++;
			else {
				mid=arr[left];
				arr[left]=arr[right];
				arr[right]=mid;
				right--;
			}
		}
		mid=arr[right];
		arr[right]=arr[l];
		arr[l]=mid;
		
		f1(arr,l,right-1);//子递归
		f1(arr,right+1,r);
	}
	
	//双向双指针扫描分区快排法
	static void f2(int[] arr,int l,int r) {
		if(l>=r)//递归出口
			return;
		
		int left=l+1,right=r,mid=0;
		while(left<=right) {//递归体
			while(left<=right&&arr[left]<=arr[l])
				left++;
			while(left<=right&&arr[right]>arr[l])
				right--;
			if(left<right) {
				mid=arr[right];
				arr[right]=arr[left];
				arr[left]=mid;
			}
		}
		mid=arr[right];
		arr[right]=arr[l];
		arr[l]=mid;
		
		f2(arr,l,right-1);//子递归
		f2(arr,right+1,r);
	}
	
	//双向和等于三指针扫描分区快排法
	static void f3(int[] arr,int l,int r) {
		if(l>=r)//递归出口
			return;
		
		int equ=l,left=l+1,right=r,mid=0;
		while(left<=right) {//递归体
			while(left<=right&&arr[left]<=arr[l]) {
				if(arr[left]==arr[l]&&equ==l)
					equ=left;
				if(arr[left]<arr[l]&&equ!=l) {
					mid=arr[left];
					arr[left]=arr[equ];
					arr[equ]=mid;
					equ++;
				}
				left++;
			}
			while(left<=right&&arr[right]>arr[l])
				right--;
			if(left<right) {
				mid=arr[right];
				arr[right]=arr[left];
				arr[left]=mid;
			}
		}
		if(equ!=l) {
			equ--;
			mid=arr[equ];
			arr[equ]=arr[l];
			arr[l]=mid;
			
			f3(arr,l,equ-1);//子递归
			f3(arr,right+1,r);
		}else {
			mid=arr[right];
			arr[right]=arr[l];
			arr[l]=mid;
			
			f3(arr,l,right-1);//子递归
			f3(arr,right+1,r);
		}
	}
	
	//以上方法均为去第一个随机数为比较主元
	//一般用三点取中值法取比较主元,如f4单指针,其他一样(取中值后和第一个数值换成为主元)
	
	//单向单指针扫描分区快排法(三点取中值为主元法)
	static void f4(int[] arr,int l,int r) {
		if(l>=r)//递归出口
			return;
		
		int left=l+1,right=r,mid=0;
		
		int midsub=l+((r-l)>>1);//三点取中值
		if(arr[l]>=arr[midsub]&&arr[midsub]>=arr[r]||
			arr[l]<=arr[midsub]&&arr[midsub]<=arr[r]) {
			mid=arr[midsub];
			arr[midsub]=arr[l];//换主元
			arr[l]=mid;
		}else if(arr[midsub]>=arr[r]&&arr[r]>=arr[l]||
				arr[midsub]<=arr[r]&&arr[r]<=arr[l]){
			mid=arr[r];
			arr[r]=arr[l];
			arr[l]=mid;
		}
		
		while(left<=right) {//递归体
			if(arr[left]<=arr[l])
				left++;
			else {
				mid=arr[left];
				arr[left]=arr[right];
				arr[right]=mid;
				right--;
			}
		}
		mid=arr[right];
		arr[right]=arr[l];
		arr[l]=mid;
		
		f4(arr,l,right-1);//子递归
		f4(arr,right+1,r);
	}
	
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		int[] arr=new int[] {0,1,9,5,4,1};
	//	f1(arr,0,5);
	//	f2(arr,0,5);
	//	f3(arr,0,5);
		f4(arr,0,5);
		for (int i : arr) {
			System.out.print(i+" ");
		}
		System.out.println();
		
	}

}

7、堆排序

思想:利用二叉树的特性,每次把最大或最小的元素比较到根节点维持一个大或小顶堆,取出根节点放到最后,直到整体有序

时间复杂度:O(nlogn)

稳定性:不稳定

分为两种:

1、小顶堆-逆向排序

2、大顶堆-顺向排序

package com.xch2.DiGui;

import java.util.*;

public class Main7 {
	
	//堆排序(小顶堆=逆序,大顶堆=顺序)
	//建小顶堆
	static void f1(int[] arr,int index,int leng) {//index初始为数组二分值减一
		if(index<0)								  //leng 初始为数组长度
			return;
		
		int left=2*index+1,right=2*index+2,mid;
		if(left==leng-1) {//最后一个父节点为单亲节点
			if(arr[left]<arr[index]) {
				mid=arr[left];
				arr[left]=arr[index];
				arr[index]=mid;
			}
		}else {
			if(arr[left]<=arr[right]&&arr[left]<arr[index]) {
				mid=arr[left];
				arr[left]=arr[index];
				arr[index]=mid;
			}else if(arr[right]<=arr[left]&&arr[right]<arr[index]) {
				mid=arr[right];
				arr[right]=arr[index];
				arr[index]=mid;
			}
		}
		
		f1(arr,index-1,leng);
	}
	
	//小顶堆转逆序数组
	static void f2(int arr[],int leng) {
		if(leng==1)
			return;
		
		f1(arr,leng/2-1,leng);
		int mid=arr[leng-1];
		arr[leng-1]=arr[0];
		arr[0]=mid;
		leng--;
		
		f2(arr,leng);
	}
	
	//建大顶堆
	static void f3(int[] arr,int index,int leng) {//index初始为数组二分值减一
		if(index<0)								  //leng 初始为数组长度
			return;
		
		int left=2*index+1,right=2*index+2,mid;
		if(left==leng-1) {//最后一个父节点为单亲节点
			if(arr[left]>arr[index]) {
				mid=arr[left];
				arr[left]=arr[index];
				arr[index]=mid;
			}
		}else {
			if(arr[left]>=arr[right]&&arr[left]>arr[index]) {
				mid=arr[left];
				arr[left]=arr[index];
				arr[index]=mid;
			}else if(arr[right]>=arr[left]&&arr[right]>arr[index]) {
				mid=arr[right];
				arr[right]=arr[index];
				arr[index]=mid;
			}
		}
		
		f3(arr,index-1,leng);
	}
	
	//大顶堆转顺序数组
	static void f4(int arr[],int leng) {
		if(leng==1)
			return;
		
		f3(arr,leng/2-1,leng);
		int mid=arr[leng-1];
		arr[leng-1]=arr[0];
		arr[0]=mid;
		leng--;
		
		f4(arr,leng);
	}
	
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		int arr[]= {5,2,8,9,2,6,7,10};
	//	f1(arr,arr.length/2-1,8);
		f2(arr,8);
	//	f3(arr,arr.length/2-1,8);
	//	f4(arr,8);
		for (int i : arr) {
			System.out.print(i+" ");
		}
		System.out.println();
		
	}
	
}

8、计数排序

思想:利用数组的特性,把元素值记录到新的辅助数组对应下标中,后顺序恢复即可(适用于元素较为集中的排序,如年龄、分数等)

时间复杂度:O(n)

稳定性:稳定

package com.xch2.DiGui;

import java.util.*;

public class Main7 {
	
	//计数顺序排序(包含负数)
	static void f5(int[] arr) {
		int cur=0,max=0,min=0;
		for (int i : arr) {
			if(i>max)
				max=i;
			else if(i<-min)
				min=-i;
		}
		int[] helper=new int[max+1];
		int[] helper1=new int[min+1];
		for (int i : arr) {
			if(i>=0)
				helper[i]++;
			else
				helper1[-i]++;
		}
		for (int i = helper1.length-1; i > 0; i--) {
			while(helper1[i]>0) {
				arr[cur]=-i;
				helper1[i]--;
				cur++;
			}
		}
		for (int i = 0; i < helper.length; i++) {
			while(helper[i]>0) {
				arr[cur]=i;
				helper[i]--;
				cur++;
			}
		}
	}
	
	//方法二
	static void f5_1(int[] arr){
		int max=0,min=0,cur=0;
		for (int i : arr) {
			if(i>max)
				max=i;
			else if(i<min)
				min=i;
		}
		for (int i = 0; i < arr.length; i++) {
			arr[i]-=min;//把所有负数转正数
		}
		int[] helper=new int[max-min+1];
		for (int i : arr) {
			helper[i]++;
		}
		for (int i = 0; i < helper.length; i++) {
			while(helper[i]!=0) {
				arr[cur]=i+min;//恢复原数组输出
				helper[i]--;
				cur++;
			}
		}
	}
	
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
//		int arr1[]= {-3,2,4,-3,66,4,66,9,0,-90,2};
//	//	f5(arr1);
//		f5_1(arr1);
//		System.out.println(Arrays.toString(arr1));
		
	}
	
}

9、桶排序

思想:利用链表的特性,通过公式把数组分为多个数段的子链表(桶,元素进入链表时是有序插入),再顺序取出即可(计数排序的进阶版:浪费率相比更低、适用数据分布相比更广)

时间复杂度:O(n)

稳定性:稳定

package com.xch2.DiGui;

import java.util.*;

public class Main7 {
	
	//桶排序(包含负数)
	static void f6(int[] arr) {
		int max=arr[0],min=arr[0],cur=0;
		for (int i : arr) {
			if(i>max)
				max=i;
			else if(i<min)
				min=i;
		}
		List<LinkedList<Integer>> bucketlist=new ArrayList<>();
		for (int i=0;i<arr.length;i++) {
			bucketlist.add(new LinkedList<Integer>());//初始化桶
		}
		for (int i : arr) {
			int num=(i-min)*arr.length/(max-min+1);//最优公式,元素放置桶
			bucketlist.get(num).add(i);
		}
		for (LinkedList<Integer> linkedlist:bucketlist) {
			Collections.sort(linkedlist);//归并排序桶中的集合
		}
		for (LinkedList<Integer> linkedlist:bucketlist) {
			for (Integer integer : linkedlist) {
				arr[cur]=integer;//遍历输出
				cur++;
			}
		}
	}
	
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
//		int arr1[]= {-3,2,4,-3,66,4,66,9,0,-90,2};
//	//	f6(arr1);
//		System.out.println(Arrays.toString(arr1));
		
	}
	
}

10、基数排序

思想:利用链表的特性,通过数字的位数(个-十-百…)渐进顺序分配到链表中,再顺序收集即可,直到最高位即整体有序(桶排序的进阶版)

时间复杂度:O(n)

稳定性:稳定

package com.xch2.DiGui;

import java.util.*;

public class Main7 {

	//基数排序(包含负数)
	static void f7(int[] arr) {
		List<Integer>[] bucketarr=new List[10];
		for (int i = 0; i < bucketarr.length; i++) {
			bucketarr[i]=new LinkedList<Integer>();//初始化数组中的集合
		}
		int maxd=0,min=arr[0];
		for (int i:arr) {
			int len=(i+"").length();
			if(len>maxd)
				maxd=len;//找最大位数
			if(i<min)
				min=i;//找最小值
		}
		if(min<0) {
			for (int i = 0; i < arr.length; i++) {
				arr[i]=arr[i]-min;//负数移位转正数
			}
		}
		int der=1,cur=0;
		for (int i = 1; i <= maxd; i++) {
			for (int j = 0; j < arr.length; j++) {
				int x=(arr[j]/der)%10;
				bucketarr[x].add(arr[j]);//入桶
			}
			for (int j = 0; j < bucketarr.length; j++) {
				for (Integer value : bucketarr[j]) {
					arr[cur]=value;//出桶
					cur++;
				}
				bucketarr[j].clear();
			}
			der*=10;
			cur=0;
		}
		if(min<0) {
			for (int i = 0; i < arr.length; i++) {
				arr[i]=arr[i]+min;//负数移位复原
			}
		}
	}
	
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
//		int arr1[]= {-3,2,4,-3,66,4,66,9,0,-90,2};
//	//	f7(arr1);
//		System.out.println(Arrays.toString(arr1));
		
	}
	
}

十大排序算法的时间复杂度:

时间复杂度效率对比:?

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-09-24 21:19:25  更:2022-09-24 21:20:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:51:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码