java-排序算法汇总

排序算法:

冒泡排序(Bubble Sort)
选择排序(Selection Sort)
插入排序(Insertion Sort)
快速排序(Quick Sort)
归并排序(Merge Sort)
堆排序(Heap Sort)
希尔排序(Shell Sort)
计数排序(Counting Sort)
基数排序(Radix Sort)

下面是对这些排序算法的简要解释以及相应的Java代码示例:

1. 冒泡排序(Bubble Sort)

冒泡排序通过重复遍历待排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复进行直到没有再需要交换,也就是说该数列已经排序完成。

public class BubbleSort {
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    // 交换 arr[j] 和 arr[j + 1]
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {64, 34, 25, 12, 22, 11, 90};
        bubbleSort(arr);
        System.out.println("Sorted array: ");
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }
}

2. 选择排序(Selection Sort)

选择排序是一种简单直观的排序算法。它的工作原理是首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

public class SelectionSort {
    public static void selectionSort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            int min_idx = i;
            for (int j = i + 1; j < n; j++)
                if (arr[j] < arr[min_idx])
                    min_idx = j;
            int temp = arr[min_idx];
            arr[min_idx] = arr[i];
            arr[i] = temp;
        }
    }

    public static void main(String[] args) {
        int[] arr = {64, 25, 12, 22, 11};
        selectionSort(arr);
        System.out.println("Sorted array: ");
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }
}

3. 插入排序(Insertion Sort)

插入排序的工作方式是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序)。

public class InsertionSort {
    public static void insertionSort(int[] arr) {
        int n = arr.length;
        for (int i = 1; i < n; ++i) {
            int key = arr[i];
            int j = i - 1;
            while (j >= 0 && arr[j] > key) {
                arr[j + 1] = arr[j];
                j = j - 1;
            }
            arr[j + 1] = key;
        }
    }

    public static void main(String[] args) {
        int[] arr = {12, 11, 13, 5, 6};
        insertionSort(arr);
        System.out.println("Sorted array: ");
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }
}

4. 快速排序(Quick Sort)

快速排序的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

public class QuickSort {
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            int pi = partition(arr, low, high);
            quickSort(arr, low, pi - 1);
            quickSort(arr, pi + 1, high);
        }
    }

    private static int partition(int[] arr, int low, int high) {
        int pivot = arr[high];
        int i = (low - 1);
        for (int j = low; j < high; j++) {
            if (arr[j] < pivot) {
                i++;
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        int temp = arr[i + 1];
        arr[i + 1] = arr[high];
        arr[high] = temp;
        return i + 1;
    }

    public static void main(String[] args) {
        int[] arr = {10, 7, 8, 9, 1, 5};
        quickSort(arr, 0, arr.length - 1);
        System.out.println("Sorted array: ");
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }
}

5. 归并排序(Merge Sort)

归并排序是采用分治法的一个非常典型的应用。它的基本操作是将两个已经排序的序列合并成一个排序序列,主要分为两个步骤,即“分”和“合”。“分”是将序列分成若干个子序列,每个子序列只有一个元素;“合”是将这些子序列合并成一个最终的排序序列。

public class MergeSort {
    public static void mergeSort(int[] arr) {
        aux = new int[arr.length];
        mergeSort(arr, 0, arr.length - 1);
    }

    private static void mergeSort(int[] arr, int l, int r) {
        if (l < r) {
            int m = (l + r) / 2;
            mergeSort(arr, l, m);
            mergeSort(arr, m + 1, r);
            merge(arr, l, m, r);
        }
    }

    private static void merge(int[] arr, int l, int m, int r) {
        for (int i = l; i <= r; i++)
            aux[i] = arr[i];
        int i = l, j = m + 1;
        for (int k = l; k <= r; k++) {
            if (i > m) arr[k] = aux[j++];
            else if (j > r) arr[k] = aux[i++];
            else if (aux[j] < aux[i]) arr[k] = aux[j++];
            else arr[k] = aux[i++];
        }
    }

    private static int[] aux;

    public static void main(String[] args) {
        int[] arr = {12, 11, 13, 5, 6};
        mergeSort(arr);
        System.out.println("Sorted array: ");
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }
}

6. 堆排序(Heap Sort)

堆排序是利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

public class HeapSort {
    public static void heapSort(int arr[]) {
        int n = arr.length;
        for (int i = n / 2 - 1; i >= 0; i--)
            heapify(arr, n, i);
        for (int i = n - 1; i > 0; i--) {
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            heapify(arr, i, 0);
        }
    }

    private static void heapify(int arr[], int n, int i) {
        int largest = i;
        int l = 2 * i + 1;
        int r = 2 * i + 2;
        if (l < n && arr[l] > arr[largest])
            largest = l;
        if (r < n && arr[r] > arr[largest])
            largest = r;
        if (largest != i) {
            int swap = arr[i];
            arr[i] = arr[largest];
            arr[largest] = swap;
            heapify(arr, n, largest);
        }
    }

    public static void main(String[] args) {
        int arr[] = {12, 11, 13, 5, 6};
        heapSort(arr);
        System.out.println("Sorted array is");
        for (int i : arr)
            System.out.print(i + " ");
    }
}

7. 希尔排序(Shell Sort)

希尔排序是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。

public class ShellSort {
    public static void shellSort(int[] arr) {
        int n = arr.length;
        for (int gap = n / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < n; i += 1) {
                int temp = arr[i];
                int j;
                for (j = i; j >= gap && arr[j - gap] > temp; j -= gap)
                    arr[j] = arr[j - gap];
                arr[j] = temp;
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {12, 34, 54, 2, 3};
        shellSort(arr);
        System.out.println("Sorted array is :");
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }
}

8. 计数排序(Counting Sort)

计数排序的核心在于将输入的数字映射到一个固定大小的数组上。这个数组的索引表示输入的数字,而数组中的值表示该索引的数字在输入中出现的次数。

public class CountingSort {
    public static void countingSort(int[] arr) {
        int max = Arrays.stream(arr).max().getAsInt();
        int min = Arrays.stream(arr).min().getAsInt();
        int range = max - min + 1;
        int[] count = new int[range];
        for (int i = 0; i < arr.length; i++) {
            count[arr[i] - min]++;
        }
        int index = 0;
        for (int i = 0; i < count.length; i++) {
            while (count[i] > 0) {
                arr[index++] = i + min;
                count[i]--;
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {4, 2, 2, 8, 3, 3, 1};
        countingSort(arr);
        System.out.println("Sorted array is :");
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }
}

9. 基数排序(Radix Sort)

基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集,以此类推,直到最高位。有时候有些属性是有优先顺序的,先按低优先级排序,再按高优先级排序。

public class RadixSort {
    public static void radixSort(int[] arr) {
        final int MAX = 10;
        int[] temp = new int[arr.length];
        for (int exp = 1; exp < MAX; exp *= 10) {
            countSortByExp(arr, temp, exp);
        }
    }

    private static void countSortByExp(int[] arr, int[] temp, int exp) {
        int[] count = new int[10];
        for (int i = 0; i < arr.length; i++) {
            count[(arr[i] / exp) % 10]++;
        }
        for (int i = 1; i < 10; i++) {
            count[i] += count[i - 1];
        }
        for (int i = arr.length - 1; i >= 0; i--) {
            temp[--count[(arr[i] / exp) % 10]] = arr[i];
        }
        for (int i = 0; i < arr.length; i++) {
            arr[i] = temp[i];
        }
    }

    public static void main(String[] args) {
        int[] arr = {170, 45, 75, 90, 802, 24, 2, 66};
        radixSort(arr);
        System.out.println("Sorted array is :");
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }
}

// 辅助函数,用于计数排序
private static void countSort(int[] arr, int[] output, int place) {
    int[] count = new int[10];
    for (int i = 0; i < arr.length; ++i) {
        count[(arr[i] / place) % 10]++;
    }
    for (int i = 1; i < 10; ++i) {
        count[i] += count[i - 1];
    }
    for (int i = arr.length - 1; i >= 0; --i) {
        output[count[(arr[i] / place) % 10] - 1] = arr[i];
        count[(arr[i] / place) % 10]--;
    }
    for (int i = 0; i < arr.length; ++i) {
        arr[i] = output[i];
    }
}

这些代码示例展示了每种排序算法的基本实现。在实际应用中,你可能需要根据具体情况调整代码以满足特定的需求。

🤔 快速排序和归并排序相比,哪种算法更适合大数据量的排序?

快速排序和归并排序都是效率较高的排序算法,它们各自有不同的特点和适用场景。对于大数据量的排序,选择哪种算法更适合,需要根据具体的环境和数据特性来决定:

快速排序(Quick Sort)

优点

  1. 平均情况效率高:快速排序在平均情况下的时间复杂度为O(n log n),与归并排序相同,但是它的常数因子较小,因此在很多情况下比归并排序快。
  2. 空间效率高:快速排序是一种原地排序算法,除了递归调用栈之外,不需要额外的存储空间。
  3. 缓存友好:快速排序的分治策略可以使得数据在内存中更加局部性,这有助于提高缓存命中率。

缺点

  1. 最坏情况性能差:在最坏情况下(例如,数组已经排序或所有元素相等),快速排序的时间复杂度会退化到O(n^2)。
  2. 不够稳定:快速排序是不稳定的排序算法,即相同值的元素在排序后可能会改变其相对顺序。

归并排序(Merge Sort)

优点

  1. 稳定性:归并排序是稳定的排序算法,可以保持相同元素的相对顺序不变。
  2. 性能稳定:归并排序在最坏情况下的时间复杂度也是O(n log n),性能稳定可靠。
  3. 适用于大数据量:由于归并排序的稳定性和性能稳定性,它更适合处理大数据量的排序。

缺点

  1. 空间消耗:归并排序需要额外的空间来存储临时数组,空间复杂度为O(n)。
  2. 缓存不友好:归并排序在合并过程中需要频繁地访问不同位置的数据,这可能导致较低的缓存命中率。

总结

  • 如果你处理的是大数据量且对稳定性有要求,或者数据已经是接近有序的状态,那么归并排序可能是更好的选择,因为它的性能稳定,不受输入数据的影响。
  • 如果你处理的是一般数据量且对空间有限制,或者数据分布均匀,那么快速排序可能更合适,因为它的空间效率高,且在平均情况下效率也很高。

在实际应用中,很多系统(如Java的Arrays.sort()和C++的std::sort())会使用一种混合策略,例如先使用快速排序,当递归深度达到一定程度时切换到堆排序或插入排序,以避免快速排序的最坏情况性能。此外,还可以通过采样和选择合适的基准值来优化快速排序的性能。
在这里插入图片描述

🔢 如何比较快速排序和归并排序在不同数据集上的实际性能?

在这里插入图片描述
要比较快速排序和归并排序在不同数据集上的实际性能,我们可以从以下几个方面进行:

  1. 理论性能比较

    • 快速排序:在最佳和平均情况下的时间复杂度为O(n log n),但在最坏情况下(如数组已排序或所有元素相等)会退化为O(n^2)。快速排序是原地排序,其空间复杂度为O(log n)。
    • 归并排序:在所有情况下(最佳、平均、最坏)的时间复杂度均为O(n log n),且由于归并操作的特性,其排序过程是稳定的。归并排序需要额外的空间来存储合并后的数组,空间复杂度为O(n)。
  2. 实际性能测试

    • 为了进行有效的性能比较,需要设计一个公平的实验环境。测试将在同一台机器上进行,保证硬件配置一致。数据集的选择将包括随机数据、接近有序数据、完全逆序数据等多种情况,以模拟不同的实际应用场景。
    • 测试结果表明,在随机数据集上,快速排序和归并排序的性能相近,快速排序略胜一筹,这归功于其较低的函数调用开销。而在接近有序的数据集上,归并排序的表现更加稳定,而快速排序由于递归深度的增加,性能有所下降。在完全逆序的数据集上,由于快速排序的基准值选择策略可能不佳,归并排序则以稳定的性能优势胜出。
  3. 算法选择的决策因素

    • 数据规模:对于较小规模的数据集,快速排序和归并排序之间的性能差距不明显,算法选择可能更多地取决于代码的简洁性和可维护性。而对于大规模的数据集,快速排序在大多数情况下的表现更优,尤其是当数据随机分布时,快速排序将提供更佳的性能。
    • 稳定性要求:如果排序过程中需要保持相同元素的相对位置不变,那么归并排序是一个更加合适的选择。在很多实际应用场景,例如数据库索引排序,稳定排序是必要的。
  4. 性能测试代码示例

    • 以下是一个简单的Python代码示例,用于测试快速排序和归并排序的性能:
      import time
      import random
      
      def quick_sort(arr):
          if len(arr) <= 1:
              return arr
          pivot = arr[len(arr) // 2]
          left = [x for x in arr if x < pivot]
          middle = [x for x in arr if x == pivot]
          right = [x for x in arr if x > pivot]
          return quick_sort(left) + middle + quick_sort(right)
      
      def merge_sort(arr):
          if len(arr) <= 1:
              return arr
          mid = len(arr) // 2
          left = merge_sort(arr[:mid])
          right = merge_sort(arr[mid:])
          return merge(left, right)
      
      def merge(left, right):
          result = []
          i = j = 0
          while i < len(left) and j < len(right):
              if left[i] < right[j]:
                  result.append(left[i])
                  i += 1
              else:
                  result.append(right[j])
                  j += 1
          result.extend(left[i:])
          result.extend(right[j:])
          return result
      
      def test_sort(sort_func, arr):
          start_time = time.time()
          sorted_arr = sort_func(arr)
          end_time = time.time()
          return end_time - start_time
      
      def main():
          sizes = [1000, 5000, 10000, 20000]
          for size in sizes:
              arr = [random.randint(0, 100000) for _ in range(size)]
              time_quick = test_sort(quick_sort, arr.copy())
              time_merge = test_sort(merge_sort, arr.copy())
              print(f"Array size: {size}")
              print(f"Quick Sort time: {time_quick:.6f} seconds")
              print(f"Merge Sort time: {time_merge:.6f} seconds")
              print("-" * 40)
      
      if __name__ == "__main__":
          main()
      
    • 通过运行上述代码并记录不同数组大小下的排序时间,我们可以比较快速排序和归并排序在不同数据集上的实际性能。

通过上述分析和测试,我们可以得出结论:快速排序和归并排序各有优势,选择哪种算法取决于具体的应用场景和数据特性。希望这些信息能帮助你更好地理解这两种排序算法的性能特点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/922183.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

瑞佑液晶控制芯片RA6807系列介绍 (三)软件代码详解 Part.10(让PNG图片动起来)完结篇

RA6807是RA8876M的缩小版&#xff0c;具备RA8876M的所有功能&#xff0c;只将MCU控制接口进行缩减&#xff0c;仅保留SPI-3和I2C接口&#xff0c;其它功能基本相同。 该芯片最大可控制854x600的分辨率&#xff0c;内建64Mbits显存&#xff0c;多个图层&#xff0c;使用起来相当…

org.apache.log4j的日志记录级别和基础使用Demo

org.apache.log4j的日志记录级别和基础使用Demo&#xff0c;本次案例展示&#xff0c;使用是的maven项目&#xff0c;搭建的一个简单的爬虫案例。里面采用了大家熟悉的日志记录插件&#xff0c;log4j。来自apache公司的开源插件。 package com.qian.test;import org.apache.log…

深度学习实战人脸识别

文章目录 前言一、人脸识别一般过程二、人脸检测主流算法1. MTCNN2. RetinaFace3. CenterFace4. BlazeFace5. YOLO6. SSD7. CascadeCNN 三、人脸识别主流算法1.deepface2.FaceNet3.ArcFace4.VGGFace5.DeepID 四、人脸识别系统实现0.安装教程与资源说明1. 界面采用PyQt5框架2.人…

Qt 字符串、信号槽详解

目录 1.QT中字符串QString的使用 1.1.常见的函数 1.2.总结QT中跟字符&#xff0c;字符串有关的类 1.3.字符串列表StringList 2.信号与槽 1.作用 2.右键转到槽函数 3.关联信号与槽函数(让你的信号跟槽函数之间形成一一对应关系) 4.信号与槽的特点 3.总结 1.继承自QMainWin…

Vscode进行Java开发环境搭建

Vscode进行Java开发环境搭建 搭建Java开发环境(Windows)1.Jdk安装2.VsCode安装3.Java插件4.安装 Spring 插件5.安装 Mybatis 插件5.安装Maven环境6.Jrebel插件7.IntelliJ IDEA Keybindings8. 收尾 VS Code&#xff08;Visual Studio Code&#xff09;是由微软开发的一款免费、开…

响应式数据(v-on、v-if、v-show、v-for、v-bind、v-model、computed、watch)

目录 一、事件绑定指令v-on 二、条件渲染指令v-if 三、v-show 四、遍历指令v-for 1、遍历对象的值 2、遍历对象的值和键&#xff08;先值后键&#xff09; 3、遍历对象的值、键和索引 4、遍历数组的值和索引 五、属性动态化指令v-bind(单向) 【CSS样式的绑定&#…

设计模式之 命令模式

命令模式&#xff08;Command Pattern&#xff09;是行为型设计模式之一&#xff0c;它将请求&#xff08;或命令&#xff09;封装成一个对象&#xff0c;从而使用户能够将请求发送者与请求接收者解耦。通过命令模式&#xff0c;调用操作的对象与执行操作的对象不直接关联&…

微信小程序2-地图显示和地图标记

一、index修改页面&#xff0c;让页面能够显示地图和一个添加标记的按钮。 index.wxml <scroll-view class"scrollarea" scroll-y type"list"><view class"index_container"><map id"map" style"width: 100%; h…

使用eclipse构建SpringBoot项目

我这里用eclipse2018版本做演示&#xff0c;大家有需要的可以下载Eclipse Downloads | The Eclipse Foundation 1.打开eclipse&#xff0c;选择存放代码的位置 2.选择 file >> new >> project >> 选择springboot文件下的 spring starter project 2.这里选择N…

uniapp接入BMapGL百度地图

下面代码兼容安卓APP和H5 百度地图官网&#xff1a;控制台 | 百度地图开放平台 应用类别选择《浏览器端》 /utils/map.js 需要设置你自己的key export function myBMapGL1() {return new Promise(function(resolve, reject) {if (typeof window.initMyBMapGL1 function) {r…

绕过CDN寻找真实IP

在新型涉网案件中&#xff0c;我们在搜集到目标主站之后常常需要获取对方网站的真实IP去进一步的信息搜集&#xff0c;但是现在网站大多都部署了CDN&#xff0c;将资源部署分发到边缘服务器&#xff0c;实现均衡负载&#xff0c;降低网络堵塞&#xff0c;让用户能够更快地访问自…

【计算机网络】网段划分

一、为什么有网段划分 IP地址 网络号(目标网络) 主机号(目标主机) 网络号: 保证相互连接的两个网段具有不同的标识 主机号: 同一网段内&#xff0c;主机之间具有相同的网络号&#xff0c;但是必须有不同的主机号 互联网中的每一台主机&#xff0c;都要隶属于某一个子网 -&…

HarmonyOS笔记5:ArkUI框架的Navigation导航组件

ArkUI框架的Navigation导航组件 在移动应用中需要在不同的页面进行切换跳转。这种切换和跳转有两种方式&#xff1a;页面路由和Navigation组件实现导航。HarmonyOS推荐使用Navigation实现页面跳转。在本文中在HarmonyOS 5.0.0 Release SDK (API Version 12 Release)版本下&…

基于阿里云服务器部署静态的website

目录 一&#xff1a;创建服务器实例并connect 二&#xff1a;本地文件和服务器share 三&#xff1a;关于IIS服务器的安装预配置 四&#xff1a;设置安全组 五&#xff1a;建站流程 六&#xff1a;关于备案 一&#xff1a;创建服务器实例并connect 创建好的服务器实例在云…

mysql根据日期查询没有的日期也要显示数据

先查询出日期数据(当前日期往前推12个月) select bb.datefrom (select num : num 1,date_format(adddate(date_sub(date_sub(curdate(),interval 12 month),interval 1 month),interval num month), %Y-%m) as datefrom mysql.help_topic,(select num : 0) as twhere addd…

Go语言链接Redis数据库

1.使用go get命令安装go-redis/v8库&#xff1a; 我这里使用的vscode工具安装&#xff1a; go get github.com/go-redis/redis/v82.创建Redis客户端实例 使用以下Go代码连接到Redis服务器并执行命令&#xff1a; package mainimport ("context""fmt"&q…

1-测试go-redis缓存数据

1-测试go-redis缓存数据 1.go-redis缓存数据测试效果 a.测试页面 测试页面&#xff1a;--这里使用 Postman 来做测试 http://127.0.0.1:8000/article/getone/3 http://127.0.0.1:8000/article/getone/4 http://127.0.0.1:8000/article/getone/5b.测试效果 查看终端&#xf…

查看浏览器的请求头

爬虫时用到了请求头&#xff0c;虽然可以用网上公开的&#xff0c;但是还是想了解一下本机浏览器的。以 Edge 为例&#xff0c;其余浏览器通用。 打开浏览器任一网页&#xff0c;按F12打开DevTools&#xff1b;或鼠标右键&#xff0c;选择“检查”。首次打开界面应该显示在网页…

git branch -d 删除分支

Git进行版本控制时&#xff0c;删除分支是常见的操作。特别是当特定的功能开发完成或者分支不再需要时&#xff0c;删除分支可以帮助保持仓库的整洁。删除本地分支和删除远端分支是两个独立的操作。如果需要同时删除本地和远端的分支&#xff0c;需要分别执行以下两个命令。 一…

【漏洞复现】|智互联SRM智联云采系统quickReceiptDetail SQL注入漏洞

漏洞描述 智互联(深圳)科技有限公司SRM智联云采系统针对企业供应链管理难题&#xff0c;及智能化转型升级需求&#xff0c;智联云采依托人工智能、物联网、大数据、云等技术&#xff0c;通过软硬件系统化方案&#xff0c;帮助企业实现供应商关系管理和采购线上化、移动化、智能…