排序算法总结

排序算法总结

定义一个通用的交换

  •    
    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

     

  • 冒泡排序
    private void bubbleSort(int[] nums) {
        for (int i = nums.length - 1; i >= 1; i--) { // 冒泡得到n-1个最大值
            for (int j = 1; j <= i; j++) {
                if (nums[j-1]>nums[j])
                    swap(nums, j, j-1);           // 交换得到较大值
            }
        }
    }

     

  • 选择排序
    private void selectionSort(int[] nums) {
        for (int i = nums.length - 1; i > 0; i--) {
            int maxIndex = 0;         // 最大元素的位置
            for (int j = 0; j <= i; j++) {
                if (nums[maxIndex]<nums[j]) {
                    maxIndex = j;
                }
            }
            swap(nums, maxIndex, i);   // 把这个最大的元素移到最后
        }
    }

     

  • 插入排序
    private void insertionSort(int[] nums) {
        for (int i = 1; i < nums.length; i++) {   // 从第二个元素开始遍历
            int j = i;
            while (j>0&&nums[j]<nums[j-1]) {     // 将当前元素移动到合适的位置
                swap(nums, j, j-1);
                j--;
            }
        }
    }

     

  • 希尔排序
    private void shellSor2(int[] nums) {
        int gap = nums.length >> 1;
        while (gap > 0) {
            for (int i = 0; i < gap; i++) {                        // 对每个子序列进行排序
                for (int j = i+gap; j < nums.length; j+=gap) {     // 插入排序的部分
                    int temp = j;
                    while (temp > i && nums[temp] < nums[temp-gap]) {
                        swap(nums, temp, temp-gap);
                        temp -= gap;
                    }
                }
            }
            gap >>= 1;
        }
    }

     

  • 归并排序
    private void mergeSort(int[] nums, int left, int right) {  // 需要左右边界确定排序范围
        if (left >= right) return;
        int mid = (left+right) / 2;
    
        mergeSort(nums, left, mid);                           // 先对左右子数组进行排序
        mergeSort(nums, mid+1, right);
    
        int[] temp = new int[right-left+1];                   // 临时数组存放合并结果
        int i=left,j=mid+1;
        int cur = 0;
        while (i<=mid&&j<=right) {                            // 开始合并数组
            if (nums[i]<=nums[j]) temp[cur] = nums[i++];
            else temp[cur] = nums[j++];
            cur++;
        }
        while (i<=mid) temp[cur++] = nums[i++];
        while (j<=right) temp[cur++] = nums[j++];
    
        for (int k = 0; k < temp.length; k++) {             // 合并数组完成,拷贝到原来的数组中
            nums[left+k] = temp[k];
        }
    }

     

  • 快速排序
    • 第一种实现
      private void quickSort(int[] nums, int left, int right) {
          if (left >= right) return;
          int lo = left+1;               // 小于分界点元素的最右侧的指针
          int hi = right;                // 大于分界点元素的最左侧的指针
          while (lo<=hi) {
              if (nums[lo]>nums[left]) { // 交换元素确保左侧指针指向元素小于分界点元素
                  swap(nums, lo, hi);
                  hi--;
              } else {
                  lo++;
              }
          }
          lo--;                          // 回到小于分界点元素数组的最右侧
          swap(nums, left, lo);          // 将分界点元素移到左侧数组最右侧
          quickSort2(nums, left, lo-1);
          quickSort2(nums, lo+1, right);
      }

       

    • 第二种实现
      private void quickSort(int[] nums, int left, int right) {
          if (left>=right) return;
          int cur = left + 1;                   // 从左侧第二个元素开始
          int lo = left;                        // 分界点为第一个元素
          while (cur <= right) {
              if (nums[cur] <= nums[left]) {    // 交换位置保证lo的左侧都是小于num[left]
                  swap(nums, lo+1, cur);
                  lo ++;
              }
              cur++;
          }
          swap(nums, left, lo);                 // 把分界点元素移动到新的分界位置
          quickSort(nums, left, lo-1);
          quickSort(nums, lo+1, right);
      }

       

  • 堆排序
    private void heapSort(int[] nums) {
        heapify(nums);                                 // 新建一个最大堆
        for (int i = nums.length - 1; i >= 1; i--) {
            swap(nums, 0, i);                       // 弹出最大堆的堆顶放在最后
            rebuildHeap(nums, 0,i-1);          // 重建最大堆
        }
    }
    
    private void heapify(int[] nums) {
        for (int i = 1; i < nums.length; i++) {
            int par = (i-1)>>1;                       // 找到父节点
            int child = i;                            // 定义子节点
            while (child>0&&nums[par]<nums[child]) {  // 从子节点到根节点构建最大堆
                swap(nums, par, child);
                child = par;
                par = (par-1) >> 1;
            }
        }
    }
    
    private void rebuildHeap(int[] nums, int par, int last) {
        int left = 2*par+1;                           // 左子节点
        int right = 2*par+2;                          // 右子节点
        int maxIndex = left;
    
        if (right<=last && nums[right]>nums[left]) {  // 找到最大子节点
            maxIndex = right;
        }
    
        if (left<=last && nums[par] < nums[maxIndex]) {// 和最大子节点比较
            swap(nums, par, maxIndex);                 // 互换到最大子节点
            rebuildHeap(nums, maxIndex, last);         // 重建最大子节点代表的子树
        }
    }

     

  • 二叉搜索树排序
    private int[] bstSort(int[] nums) {
        TreeNode root = new TreeNode(nums[0]);   // 构建根节点
        for (int i = 1; i < nums.length; i++) {  // 将所有的元素插入到二叉搜索树中
            buildTree(root, nums[i]);
        }
        inorderTraversal(root, nums, new int[1]);// 中序遍历获取二叉树中的所有节点
        return nums;
    }
    
    private void inorderTraversal(TreeNode node, int[] nums, int[] pos) {
        if (node == null) return;
        inorderTraversal(node.left, nums, pos);
        nums[pos[0]++] = node.val;
        inorderTraversal(node.right, nums, pos);
    }
    
    private void buildTree(TreeNode node, int num) {
        if (node == null) return;
        if (num >= node.val) {                   // 插入到右子树中
            if (node.right == null) {
                node.right = new TreeNode(num);
            } else {
                buildTree(node.right, num);
            }
        } else {                                 // 插入到左子树中
            if (node.left == null) {
                node.left = new TreeNode(num);
            } else {
                buildTree(node.left, num);
            }
        }
    }
    
    static class TreeNode {   // 树节点的数据结构
        int val;
        TreeNode left;
        TreeNode right;
    
        public TreeNode(int val) {
            this.val = val;
        }
    }

     

  • 计数排序
    private void countSort(int[] nums) {
        int min = Integer.MAX_VALUE;
        int max = Integer.MIN_VALUE;
        for (int num : nums) {            // 找到最大最小值
            min = Math.min(min, num);
            max = Math.max(max, num);
        }
        int[] count = new int[max-min+1]; // 建立新数组
        for (int num : nums) {            // 统计每个元素出现频率
            count[num-min]++;
        }
        int cur = 0;
        for (int i = 0; i < count.length; i++) {  // 根据出现频率把计数数组中的元素放回到旧数组中
            while (count[i]>0) {
                nums[cur++] = i+min;
                count[i]--;
            }
        }
    }

     

  • 桶排序
    private void bucketSort(int[] nums) {
        int INTERVAL = 100;               // 定义桶的大小
        int min = Integer.MAX_VALUE;
        int max = Integer.MIN_VALUE;
        for (int num : nums) {            // 找到数组元素的范围
            min = Math.min(min, num);
            max = Math.max(max, num);
        }
        int count = (max - min + 1);      // 计算出桶的数量
        int bucketSize = (count % INTERVAL == 0) ?( count / INTERVAL) : (count / INTERVAL+1);
        List<Integer>[] buckets = new List[bucketSize];
        for (int num : nums) {            // 把所有元素放入对应的桶里面
            int quotient = (num-min) / INTERVAL;
            if (buckets[quotient] == null) buckets[quotient] = new ArrayList<>();
            buckets[quotient].add(num);
        }
        int cur = 0;
        for (List<Integer> bucket : buckets) {
            if (bucket != null) {
                bucket.sort(null);       // 对每个桶进行排序
                for (Integer integer : bucket) {  // 还原桶里面的元素到原数组
                    nums[cur++] = integer;
                }
            }
        }
    }

     

  • 基数排序
    private void radixSort(int[] nums) {
        int max = -1;
        int min = 1;
        for (int num : nums) {         // 计算最大最小值
            max = Math.max(max, num);
            min = Math.min(min, num);
        }
        max = Math.max(max, -min);     // 求得绝对值最大的值
        int digits = 0;
        while (max > 0) {              // 计算绝对值最大的值的位数
            max /= 10;
            digits++;
        }
        List<Integer>[] buckets = new List[19]; // 建一个包含所有位数的数组
        for (int i = 0; i < buckets.length; i++) {
            buckets[i] = new ArrayList<>();
        }
        int pos;
        int cur;
        for (int i = 0, mod = 1; i < digits; i++, mod*=10) { // 对十进制每一位进行基数排序
            for (int num : nums) {                 // 扫描数组将值放入对应的桶
                pos = (num / mod) % 10;
                buckets[pos+9].add(num);
            }
            cur = 0;
            for (List<Integer> bucket : buckets) { // 将桶内元素放回到数组里面
                if (bucket!=null) {
                    for (Integer integer : bucket) {
                        nums[cur++] = integer;
                    }
                    bucket.clear();                // 将桶清空
                }
            }
        }
    }

     

  • 总结
排序算法  最好情况 平均情况 最差情况 空间复杂度 稳定性
冒泡排序 n2 n2   1
选择排序 n2 n2   1  
插入排序 n2   1
希尔排序 nlogn n4/3   1  
二叉树排序 nlogn nlogn   n
归并排序 nlogn nlogn   n
快速排序 nlogn nlogn   logn  
堆排序 nlogn nlogn   1  
计数排序   n+r   n+r
桶排序   n+r   n+r
基数排序        
posted @ 2021-07-21 11:20  唉我头发呢  阅读(34)  评论(0)    收藏  举报
Live2D