8种排序算法
数据结构中常用的8种排序算法:冒泡、选择、插入、希尔、快速、归并、基数、堆排序。
算法性能对比
算法 | 最好情况 | 最坏情况 | 平均 | 空间复杂度 | 排序方式 | 稳定性 |
---|---|---|---|---|---|---|
冒泡 | O(n) | O( n 2 n^2 n2) | O( n 2 n^2 n2) | O(1) | In-place | 稳定 |
选择 | O( n 2 n^2 n2) | O( n 2 n^2 n2) | O( n 2 n^2 n2) | O(1) | In-place | 不稳定 |
插入 | O(n) | O( n 2 n^2 n2) | O( n 2 n^2 n2) | O(1) | In-place | 稳定 |
希尔 | O(n l o g 2 log^2 log2n) | O(n l o g 2 log^2 log2n) | O(nlogn) | O(1) | In-place | 不稳定 |
归并 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | Out-place | 稳定 |
快速 | O(nlogn) | O( n 2 n^2 n2) | O(nlogn) | O(logn) | In-place | 不稳定 |
基数 | O(n*k) | O(n*k) | O(n*k) | O(n+k) | Out-place | 稳定 |
堆 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | In-place | 不稳定 |
算法代码
- 冒泡排序
public class BubbleSort {
private static int count = 0;
// 第一次将最小的数放在了最左边
public void bubbleSort(int[] nums){
int len = nums.length;
boolean flag = false;
for(int i = 0;i< len-1;i++){
for(int j = i+1;j<len;j++){
if(nums[i] > nums[j]){
flag = true;
count++;
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
if(!flag){
break;
}else{
flag = false;
}
for (int num : nums) {
System.out.print(num+"\t");
}
System.out.println();
}
System.out.printf("执行了%d次",count);
}
// 第一次将最大的数放在最右边
public void bubbleSort2(int[] nums){
int len = nums.length;
boolean flag = false;
for(int i = 0;i< len-1;i++){
for(int j = 0;j<len-1-i;j++){
count++;
if(nums[j] > nums[j+1]){
flag = true;
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
}
}
if(!flag){
break;
}else{
flag = false;
}
for (int num : nums) {
System.out.print(num+"\t");
}
System.out.println();
}
System.out.printf("执行了%d次",count);
}
public static void main(String[] args) {
new BubbleSort().bubbleSort2(new int[]{10,2,3,1,7,5,4,6,8});
}
}
- 选择排序
public class SelectSort {
public static void main(String[] args) {
int[] nums = {3,4,2,9,6,1,-2,8,5,7};
for(int i = 0;i < nums.length;i++){
int min = nums[i];
int index = i;
for(int j = i+1; j < nums.length;j++){
if(nums[j] < min){
min = nums[j];
index = j;
}
}
if(index != i){
nums[index] = nums[i];
nums[i] = min;
}
}
for (int num : nums) {
System.out.printf(num+"\t");
}
}
}
- 插入排序
public class InsertSort {
/*
* 需要移动数组
* 速度比冒泡快些
* */
public static void insertSort(int[] num){
for(int i=1;i<num.length;i++){
int index = i-1;
int val = num[i];
// 先和它前面的一个数比较
while (index >=0 && val < num[index]){
num[index+1] = num[index];
index--;
}
// 相等时说明没有动
if(index + 1 != i)
num[index+1] = val;
}
for (int i : num) {
System.out.print(i+"\t");
}
}
public static void main(String[] args) {
int[] nums = {3,4,2,9,6,1,-2,8,5,7};
insertSort(nums);
}
}
- 希尔排序
public class ShellSort {
// 交换式 效率低·
public static void shellSort(int[] nums){
int length = nums.length;
for(int gap = length / 2;gap > 0;gap /= 2){
// 对每一组进行排序
for(int i = gap;i<length;i++){
for (int j = i-gap; j >= 0; j -= gap) {
if(nums[j] > nums[j+gap]){
int temp = nums[j+gap];
nums[j+gap] = nums[j];
nums[j] = temp;
}
}
}
}
for (int num : nums) {
System.out.print(num+"\t");
}
}
// 移动式 速度快
public static void shellSortByMove(int[] nums){
int length = nums.length;
for(int gap = length / 2;gap > 0;gap /= 2){
// 对每一组进行插入排序
for(int i = gap;i<length;i++){
int j = i-gap;
int val = nums[i];
while(j>=0 && nums[j] > val){
nums[j+gap] = nums[j];
j -= gap;
}
nums[j+gap] = val;
}
}
for (int num : nums) {
System.out.print(num+"\t");
}
}
public static void main(String[] args) {
int[] nums = {3,4,2,9,6,1,-2,8,5,7};
shellSortByMove(nums);
}
}
- 归并排序
public class MergeSort {
public static void main(String[] args) {
int[] nums = {2,8,1,4,3,7,9};
mergeSort(nums,0,nums.length-1,new int[nums.length]);
System.out.println(Arrays.toString(nums));
}
public static void mergeSort(int[] nums,int left,int right,int[] temp){
if(left < right){
// 分
int mid = left+(right-left)/2;
mergeSort(nums,left,mid,temp);
mergeSort(nums,mid+1,right,temp);
// 治
merge(nums,left,mid,right,temp);
}
}
/**
*
* @param arr 原数组
* @param left 左索引
* @param mid 中间元素索引
* @param right 右索引
* @param temp 临时数组
*/
public static void merge(int[] arr,int left,int mid,int right,int[] temp){
int i = left,j = mid+1;
int t = 0;
//1. 比较两边有序数组,依次将较小的插入到temp
while(i <= mid && j<= right){
if(arr[i] <= arr[j]){
temp[t++] = arr[i++];
}else{
temp[t++] = arr[j++];
}
}
//2. 将两边剩余元素插入到temp
while(i <= mid){
temp[t++] = arr[i++];
}
while(j <= right){
temp[t++] = arr[j++];
}
//3. 将temp拷贝到 arr
t = 0;
for (int k = left; k <= right; k++) {
arr[k] = temp[t++];
}
}
}
- 基数排序
public class RadixSort {
public static void main(String[] args) {
int[] nums = {20,8,15,104,322,79,98};
radixSort(nums);
}
public static void radixSort(int[] nums){
// 首先要找到最大的数的长度
int mmaxNum = nums[0];
for(int i=1;i<nums.length;i++){
if(mmaxNum < nums[i])
mmaxNum = nums[i];
}
int length = mmaxNum+ "".length();
// 定义10个桶,二维数组, 数字0-9
int[][] bucket = new int[10][nums.length];
// 定义存放每个桶中的元素的数组
int[] dataCount = new int[10];
for (int i = 0; i < length; i++) {
for(int j=0;j<nums.length;j++){
int num = nums[j] / (int)Math.pow(10,i) % 10;
// 将每一个数按照对应为放入到对应的桶中取去
bucket[num][dataCount[num]] = nums[j]; // 存的是nums[j],不是num
dataCount[num]++;
}
// 将分好的数重新放到原数组中
int index = 0;
// 遍历每一个痛,不为空时
for(int k = 0;k< bucket.length;k++){
if(dataCount[k] > 0){
for(int l = 0;l < dataCount[k];l++){
nums[index++] = bucket[k][l];
}
}
dataCount[k] = 0;
}
}
System.out.println(Arrays.toString(nums));
}
}
- 快速排序
public class QuickSort {
public static void main(String[] args) {
int[] nums = {4,6,1,3,5,2,7};
quickSort(nums,0, nums.length-1);
for (int num : nums) {
System.out.print(num+"\t");
}
}
// 第一种
public static void quickSort(int[] nums,int left,int right){
// 终止条件
if (left >= right)return;
// 以第一个数为基准数
int num = nums[left];
int i = left,j = right;
while(i < j){
// 先从右至左寻找第一个小于基准的数,
while(i<j && nums[j] >= num)j--;
if(i<j)
nums[i++] = nums[j]; //并将基准位置替换成该数, 并将左指针后移一位
// 再从左向右寻找第一个比基准大的元素
while(i<j && nums[i] < num)i++;
if(i<j)
nums[j--] = nums[i];// 将该数放置右边对应位置,并将右指针左移一位
}
// 一次排序过后,最终i==j,并将基准放置该待的地方
nums[i] = num;
quickSort(nums,left,i-1);
quickSort(nums,i+1,right);
}
// 第二种实现方式
public static int[] quick_sort(int[] num, int l, int r){
//r为数组元素总个数,last下标等于r-1
int first=l,last=r-1,key=num[first];
while(first<last){
while(first<last&&num[last]>=key){
--last;
}
//如果值小于 key分界值 交换
num[first]=num[last];
while(first<last&&num[first]<key){
++first;
}
//如果值大于key分界值 交换
num[last]=num[first];
}
num[first]=key;
//递归左右部分进行快排
if (first>l) {
num=quick_sort(num, l, first);
}
if (first+1<r){
num=quick_sort(num,first+1,r);
}
return num;
}
}
- 堆排序
public class HeapSort {
public static void adjust(int[] arr,int i,int len){
int temp = arr[i]; //记录当前值
for(int k = i * 2+1;k < len;k = k*2+1){
// 比较左右子树哪个大,记录较大值的索引
if(k+1 <len && arr[k] < arr[k+1]){
k++;
}
// 将较大值放到父节点
if(arr[k] > temp){
arr[i] = arr[k];
i = k;
}else {
break;
}
}
// 更新父节点的值
arr[i] = temp;
}
public static void heapSort(int[] arr){
// 将数组构建一个堆
for(int i = arr.length/2-1;i >= 0 ;i--){
adjust(arr,i, arr.length);
}
// 排序,先交换
for(int j = arr.length-1;j >= 0 ;j--){
int temp = arr[j];
arr[j] = arr[0];
arr[0] = temp;
adjust(arr,0,j);
}
System.out.println(Arrays.toString(arr));
}
public static void main(String[] args) {
int[] arr = {1,7,4,6,8,5,9,3};
heapSort(arr);
}
}
如有书写错误的地方,欢迎指正。