数据结构——排序

排序

冒泡排序:

在无序区间,通过相邻的数比较,将最大的数冒泡到无序区间的最后,重复前面的步骤,直到所有元素都已排序完。

public class MySort {
    // 冒泡排序:
    public static void bubbleSort(int[] arr){
        int bound = 0;
        for (;bound < arr.length; ++bound){
            for (int cur = arr.length-1; cur > bound; --cur){
                if (arr[cur] < arr[cur-1]){
                    swap(arr,cur,cur-1);
                }
            }
        }
    }
}
时间复杂空间复杂度稳定性
最好平均最坏
O(n)O(n^2)O(n^2)O(1)稳定
数据有序数据逆序

插入排序:

每次选择无序区间的第一个元素,在有序区间内选择合适的位置插入。

public class MySort {
    public static void insertSort(int[] arr){
        for (int i = 0; i < arr.length; ++i){
            int flag = arr[i];  // 无序和有序区间的分界
            int j = i - 1;
            for (; j >= 0 && arr[j] > flag; --j){
                arr[j + 1] = arr[j];
            }
            arr[j + 1] = flag;
        }
    }
}
时间复杂空间复杂度稳定性
最好平均最坏
O(n)O(n^2)O(n^2)O(1)稳定
数据有序数据逆序

希尔排序:

先选定一个数n,将待排序区间分成若干个组,距离为n的分在同一组内,进行排序,然后接着重复前面的步骤,直到组内距离为1,进行整组排序。

(希尔排序是对插入排序的优化)

public class MySort {
    // 希尔排序:
    public static void shellSort(int[] arr){
        // 使用希尔序列
        int gap = arr.length / 2;
        while (gap >= 1){
            // 分组插排
            _shellSort(arr, gap);
            gap /= 2;
        }
    }
    // 辅助希尔排序:与插入排序类似
    public static void _shellSort(int[] arr, int gap){
        for (int bound = gap; bound < arr.length; bound++){
            int num = arr[bound];
            int cur = bound - gap;
            for (; cur >= 0; cur -= gap){
                if (arr[cur] > num){
                    arr[cur + gap] = arr[cur];
                }else
                    break;
            }
            arr[cur + gap] = num;
        }
    }
}
时间复杂空间复杂度稳定性
最好平均最坏
O(n)O(n^1.3)O(n^2)O(1)不稳定
数据有序较难构造

选择排序:

每一次从无序区间选出最大/最小的元素,存放在无序区间的最后/最前。直到将所有数据排序完毕。

public class MySort {
	 // 选择排序:
    public static void selectSort(int[] arr){
        int bound = 0;  // 标志 bound 前为已排序, bound 后为未排序
        for (; bound < arr.length-1; ++bound){
            for (int cur = bound + 1; cur < arr.length; ++cur){
                if (arr[cur] < arr[bound]){
                    swap(arr,cur,bound);
                }
            }
        }
    }
        // 交换
    public static void swap(int[] arr, int x, int y){
        int tmp = arr[x];
        arr[x] = arr[y];
        arr[y] = tmp;
    }
}    
时间复杂度空间复杂度稳定性
O(n^2)O(1)不稳定
数据不敏感数据不敏感

快速排序:

采用分治思想:从待排序区间选择一个数作为基准值,将待排序区间中比基准值小的放在基准值左边,大的放在基准值右边,对左右两个小区间重复步骤,直到区间长度为1,排序结束。

public class MySort {
    // 快速排序:
    public static void quickSort(int[] arr){
        _quickSort(arr,0,arr.length-1);
    }
    // 辅助快速排序
    public static void _quickSort(int[] arr, int left, int right){
        if (left >= right){
            return;
        }
        // 获取 基准值 所在位置
        int index = partition(arr,left,right);
        // 递归处理 index 左/右 区间
        _quickSort(arr,left,index-1);
        _quickSort(arr,index+1,right);
    }
    public static int partition(int[] arr, int left, int right){
        // 选取基准值
        int model = arr[right];
        int i = left, j = right;
        while (i < j){
            // 找到比基准值大的值
            while (i < j && arr[i] <= model)
                i++;
            // 找到比基准值小的值
            while (i < j && arr[j] >= model)
                j--;
            // 交换这两个元素
            swap(arr,i,j);
        }
        // 当 i 和 j 相等时,交换当前位置的值 和 基准值,使得基准值位于数组的“中间”
        swap(arr,i,right);
        return i;
    }

    // 使用非递归实现快速排序
    public static void quickSortByLoop(int[] arr){
        Stack<Integer> stack = new Stack<>();
        // 将第一组数据入栈
        stack.push(0);
        stack.push(arr.length-1);
        // 循环取栈顶元素 进行 partition 操作
        while (!stack.isEmpty()){
            int end = stack.pop();
            int start = stack.pop();
            if (start >= end){
                // 空区间 只有一个元素
                continue;
            }
            // 调用 partition
            int index = partition(arr,start,end);
            // 把得到的子区间入栈
            stack.push(end);
            stack.push(index + 1);
            stack.push(index - 1);
            stack.push(start);
        }
    }
}    
时间复杂——空间复杂稳定性
最好平均最坏最好平均最坏
O(n*log(n))O(n*log(n))O(n^2)O(log(n))O(log(n))O(log(n))O(n)不稳定

归并排序:

采用分治法,先将每个子序列有序,在将已有序的子序列合并进行排序,直到最后合并为一个完全有序表。

import java.util.Arrays;

public class MySort {

    // 归并排序:
    public static void mergeSort(int[] arr){
        _mergeSort(arr, 0, arr.length);
    }
    public static void _mergeSort(int[] arr, int left, int right){
        if (right - left <= 1){
            return;
        }

        int mid = (left + right) / 2;
        _mergeSort(arr, left, mid);
        _mergeSort(arr, mid, right);
        // 合并左右两个有序数组
        merge(arr, left, mid, right);
    }
    public static void merge(int[] arr, int left, int mid, int right){
        int[] tmp = new int[right - left]; // 临时数组,用来存放合并后的结果
        int tmpSize = 0;
        int l = left;
        int r = mid;
        while (l < mid && r < right){
            if (arr[l] <= arr[r]){
                tmp[tmpSize] = arr[l];
                tmpSize++;
                l++;
            }else{
                tmp[tmpSize] = arr[r];
                tmpSize++;
                r++;
            }
        }

        while (l < mid){
            tmp[tmpSize] = arr[l];
            tmpSize++;
            l++;
        }
        while (r < right){
            tmp[tmpSize] = arr[r];
            tmpSize++;
            r++;
        }
        for (int i = 0; i < tmp.length; ++i){
            arr[left+i] = tmp[i];
        }
    }

    //非递归归并排序
    public static void mergeSortByLoop(int[] arr){
        // 外层循环
        // 第一次是将长度为 1 的有序数组两两合并
        // 第二次是将长度为 2 的有序数组两两合并
        // 第三次是将长度为 4 的有序数组两两合并
        for (int gap = 1; gap < arr.length; gap *= 2){
            // 里层循环
            // 让两个相邻的数组合并
            for (int i = 0; i < arr.length; i += 2*gap){
                int left = i;
                int mid = i + gap;
                if (mid >= arr.length){
                    mid = arr.length;
                }
                int right = i + 2*gap;
                if (right >= arr.length){
                    right = arr.length;
                }
                merge(arr,left,mid,right);
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {9,5,2,6,3,6,8};
        mergeSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}
时间复杂度空间复杂度稳定性
O(n*log(n))O(n)稳定
数据不敏感数据不敏感

堆排序:

public class MySort {
    // 堆排序:
    public static void heapSort(int[] arr){
        // 1.建堆
        creatHeap(arr);
        // 2.交换堆顶元素和最后一个元素,删除最后一个元素并向下调整
        int heapSize = arr.length;
        for (int i = 0; i < arr.length; ++i){
            // 交换堆顶和最后一个元素
            swap(arr,0,heapSize-1);
            // 删除最后一个元素
            heapSize--;
            // 向下调整
            shiftHeap(arr,heapSize,0);
        }
    }
    // 向下调整
    public static void shiftHeap(int[] arr, int size, int index){
        int parent = index;
        int child = 2 * parent + 1;
        while (child < size){
            // 找出左右子树较大的
            if (child+1 < size && arr[child + 1] > arr[child]){
                child += 1;
            }
            if (arr[parent] < arr[child]){
                swap(arr,parent,child);
            }else
                break;

            parent = child;
            child = 2 * parent + 1;
        }
    }
    // 建堆
    public static void creatHeap(int[] arr){
        for (int i = (arr.length - 1 - 1)/2; i >= 0; --i){
            shiftHeap(arr,arr.length,i);
        }
    }
}
时间复杂度空间复杂度稳定性
O(n*log(n))O(1)不稳定
数据不敏感数据不敏感
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值