赞
踩
排序:快速排序法、堆排序法、冒泡排序法、归并排序法以及插入排序法还有希尔排序法、选择排序法、基数排序法,桶排序法、冒泡改进排序法、快速改进排序法、O(NlogN)排序法,基数桶排序法、外部排序法、内部排序法、交错排序法还有一些较少被使用的排序算法,如希尔伯特曲线排序、梳排序、块排序、序位排序。
Java实现快速排序的代码(来源:https://www.geeksforgeeks.org/quick-sort/ ):
// Java implementation of QuickSort
- import java.io.*;
-
-
-
- class GFG {
-
-
-
- // A utility function to swap two elements
-
- static void swap(int[] arr, int i, int j)
-
- {
-
- int temp = arr[i];
-
- arr[i] = arr[j];
-
- arr[j] = temp;
-
- }
-
-
-
- /* This function takes last element as pivot, places
- the pivot element at its correct position in sorted
- array, and places all smaller (smaller than pivot)
- to left of pivot and all greater elements to right
- of pivot */
-
- static int partition(int[] arr, int low, int high)
-
- {
-
-
-
- // pivot
-
- int pivot = arr[high];
-
-
-
- // Index of smaller element and
-
- // indicates the right position
-
- // of pivot found so far
-
- int i = (low - 1);
-
-
-
- for (int j = low; j <= high - 1; j++) {
-
-
-
- // If current element is smaller
-
- // than the pivot
-
- if (arr[j] < pivot) {
-
-
-
- // Increment index of
-
- // smaller element
-
- i++;
-
- swap(arr, i, j);
-
- }
-
- }
-
- swap(arr, i + 1, high);
-
- return (i + 1);
-
- }
-
-
-
- /* The main function that implements QuickSort
- arr[] --> Array to be sorted,
- low --> Starting index,
- high --> Ending index
- */
-
- static void quickSort(int[] arr, int low, int high)
-
- {
-
- if (low < high) {
-
-
-
- // pi is partitioning index, arr[p]
-
- // is now at right place
-
- int pi = partition(arr, low, high);
-
-
-
- // Separately sort elements before
-
- // partition and after partition
-
- quickSort(arr, low, pi - 1);
-
- quickSort(arr, pi + 1, high);
-
- }
-
- }
-
-
-
- // Function to print an array
-
- static void printArray(int[] arr, int size)
-
- {
-
- for (int i = 0; i < size; i++)
-
- System.out.print(arr[i] + " ");
-
-
-
- System.out.println();
-
- }
-
-
-
- // Driver Code
-
- public static void main(String[] args)
-
- {
-
- int[] arr = { 10, 7, 8, 9, 1, 5 };
-
- int n = arr.length;
-
-
-
- quickSort(arr, 0, n - 1);
-
- System.out.println("Sorted array: ");
-
- printArray(arr, n);
-
- }
-
- }
-
-
-
- // This code is contributed by Ayush Choudhary
下面是用Java实现冒泡排序的算法:
- /*
- * 冒泡排序方法
- * for循环外层从0开始到数组最后一个元素-1, 内层for循环从0开始到i前面的元素
- * 比较arr[j]和arr[j+1]的大小,如果arr[j]大于arr[j+1],则交换位置
- */
- public static void bubbleSort(int[] arr) {
- int temp;
- for (int i = 0; i < arr.length - 1; i++) {
- for (int j = 0; j < arr.length - 1 - i; j++) {
- if (arr[j] > arr[j + 1]) { // 交换变量位置
- temp = arr[j];
- arr[j] = arr[j + 1];
- arr[j + 1] = temp;
- }
- }
- }
- }
当然,冒泡排序法,当循环到其中一圈的时候,假如已经有序了,就没有必要再向后进行循环,详细的方法看10.冒泡改进排序。
下面是一个用Java实现堆排序的算法:
- /**
- * 堆排序
- *
- * @param arr
- * 待排序列
- */
- public static void heapSort(int[] arr) {
- // build heap
- for (int i = arr.length / 2 - 1; i >= 0; i--) {
- heapAdjust(arr, i, arr.length);
- }
-
- for (int i = arr.length - 1; i > 0; i--) {
- swap(arr, 0, i);
- heapAdjust(arr, 0, i);
- }
- }
-
- /**
- * 调整堆
- *
- * @param arr
- * 待排序列
- * @param parent
- * 父节点
- * @param length
- * 待排序列尾元素索引
- */
- public static void heapAdjust(int[] arr, int parent, int length) {
- int temp = arr[parent]; // temp保存当前父节点
- int child = 2 * parent + 1; // 先获得左孩子
-
- while (child < length) {
- // 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
- if (child + 1 < length && arr[child] < arr[child + 1]) {
- child++;
- }
-
- // 如果父结点的值已经大于孩子结点的值,则直接结束
- if (temp >= arr[child])
- break;
-
- // 把孩子结点的值赋给父结点
- arr[parent] = arr[child];
-
- // 选取孩子结点的左孩子结点,继续向下筛选
- parent = child;
- child = 2 * child + 1;
- }
- arr[parent] = temp;
- }
-
- /**
- * 交换元素位置
- *
- * @param arr
- * 待交换列表
- * @param a
- * 元素下标
- * @param b
- * 元素下标
- */
- public static void swap(int[] arr, int a, int b) {
- int temp = arr[a];
- arr[a] = arr[b];
- arr[b] = temp;
- }
下面是一个用Java实现归并排序的算法,并带有中文注释:
- /**
- * 归并排序
- *
- * @param arr
- * 待排序列
- */
- public static void mergeSort(int[] arr) {
- mergeSortC(arr, 0, arr.length - 1);
- }
-
- /**
- * 递归调用函数
- *
- * @param arr
- * 待排序列
- * @param left
- * 左边界
- * @param right
- * 右边界
- */
- public static void mergeSortC(int[] arr, int left, int right) {
- if (left == right)
- return;
- int mid = (left + right) / 2;
- // 左边数组排序
- mergeSortC(arr, left, mid);
- // 右边数组排序
- mergeSortC(arr, mid + 1, right);
- // 合并两个有序数组
- merge(arr, left, mid, right);
- }
-
- /**
- * 合并两个有序数组
- *
- * @param arr
- * 排序数组
- * @param left
- * 左边界
- * @param mid
- * 中间
- * @param right
- * 右边界
- */
- public static void merge(int[] arr, int left, int mid, int right) {
- int[] temp = new int[right - left + 1];
- int i = left;
- int j = mid + 1;
- int k = 0;
-
- // 把较小的数先移到新数组中
- while (i <= mid && j <= right) {
- if (arr[i] <= arr[j]) {
- temp[k++] = arr[i++];
- } else {
- temp[k++] = arr[j++];
- }
- }
-
- // 把左边剩余的数移入数组
- while (i <= mid) {
- temp[k++] = arr[i++];
- }
-
- // 把右边剩余的数移入数组
- while (j <= right) {
- temp[k++] = arr[j++];
- }
-
- // 把新数组中的数覆盖arr数组
- for (int k2 = 0; k2 < temp.length; k2++) {
- arr[k2 + left] = temp[k2];
- }
- }
下面是一个使用Java实现插入排序算法的语句,并带有中文注释:
- /**
- * 插入排序
- *
- * @param arr
- * 待排序列
- */
- public static void insertionSort(int[] arr) {
- for (int i = 1; i < arr.length; i++) {
- int j = i - 1;
- int temp = arr[i];
- // 寻找插入位置并移动数据
- while (j >= 0 && arr[j] > temp) {
- arr[j + 1] = arr[j];
- j--;
- }
- arr[j + 1] = temp;
- }
- }
下面是一个使用Java实现希尔排序算法的语句,并带有详细注释:
- /**
- * 希尔排序
- *
- * @param array
- * 待排序列
- */
- public static void shellSort(int[] array) {
- int increment = array.length / 2;
- while (increment >= 1){
- for (int i = increment; i < array.length; i++) {
- int j = i - increment;
- int temp = array[i];
- // 寻找插入位置并移动数据
- while (j >= 0 && array[j] > temp) {
- array[j + increment] = array[j];
- j -= increment;
- }
- array[j + increment] = temp;
- }
- // 设置新的增量
- increment /= 2;
- }
- }
下面是一个使用Java实现基数排序算法的语句
基数排序的代码实现如下:
- // 获取数组中最大元素的位数
- int getMaxDigit(int[] array) {
- int maxValue = array[0];
- for (int i = 1; i < array.length; i++) {
- if (maxValue < array[i]) {
- maxValue = array[i];
- }
- }
- return getNumLenght(maxValue);
- }
-
- // 基数排序实现
- public void radixSort(int[] array, int radix) {
- // 获取数组中最大元素的位数
- int maxDigit = getMaxDigit(array);
-
- // 申请桶
- int[][] buckets = new int[radix][array.length];
- // 申请计数器,记录每个桶中实际存放了多少个数据
- int[] counters = new int[radix];
-
- // 从低位到高位开始进行排序
- for (int d = 0; d < maxDigit; d++) {
- // 将数据放入桶中
- for (int i = 0; i < array.length; i++) {
- int bucketIndex = getDigit(array[i], d);
- buckets[bucketIndex][counters[bucketIndex]] = array[i];
- counters[bucketIndex]++;
- }
-
- // 将桶中数据放回原始数组
- int index = 0;
- for (int i = 0; i < radix; i++) {
- for (int j = 0; j < counters[i]; j++) {
- array[index] = buckets[i][j];
- index++;
- }
- // 重置计数器
- counters[i] = 0;
- }
- }
- }
下面是一个使用Java实现选择排序算法的语句,并带有中文注释:
- /**
- * 选择排序
- *
- * @param array
- * 待排序列
- */
- public static void selectionSort(int[] array) {
- int len = array.length;
- for (int i = 0; i < len - 1; i++) {
- //记录最小值的下标
- int minIndex = i;
- // 找出最小值
- for (int j = i + 1; j < len; j++) {
- if (array[minIndex] > array[j]) {
- minIndex = j;
- }
- }
- // 确保不是本身的位置
- if (minIndex != i) {
- int temp = array[minIndex];
- array[minIndex] = array[i];
- array[i] = temp;
- }
- }
- }
下面是一个使用Java实现桶排序算法的语句,并带有中文注释:
- /**
- * 桶排序
- *
- * @param array
- * 待排序列
- * @param bucketSize
- * 每个桶所能放置多少个不同数值
- */
- public static void bucketSort(int[] array, int bucketSize) {
- if (array.length == 0) {
- return;
- }
-
- // 计算桶的数量
- int minValue = array[0];
- int maxValue = array[0];
- for (int i = 1; i < array.length; i++) {
- if (array[i] < minValue) {
- minValue = array[i];
- } else if (array[i] > maxValue) {
- maxValue = array[i];
- }
- }
- int bucketCount = (maxValue - minValue) / bucketSize + 1;
- int[][] buckets = new int[bucketCount][0];
-
- // 利用映射函数将数据分配到各个桶中
- for (int i = 0; i < array.length; i++) {
- int index = (array[i] - minValue) / bucketSize;
- buckets[index] = arrAppend(buckets[index], array[i]);
- }
-
- int position = 0;
- // 对每个桶进行排序,这里使用了快速排序
- for (int[] bucket : buckets) {
- quickSort(bucket);
- for (int value : bucket) {
- array[position++] = value;
- }
- }
- }
下面是一个使用Java实现冒泡改进排序算法的语句,并带有中文注释:
- /**
- * 冒泡改进排序
- *
- * @param array
- * 待排序列
- */
- public static void improvedBubbleSort(int[] array) {
- int len = array.length;
- boolean flag;// 标志位,标志是否发生了交换
- for (int i = 0; i < len - 1; i++) {
- flag = false;
- for (int j = 0; j < len - 1 - i; j++) {
- if (array[j] > array[j + 1]) {
- int temp = array[j];
- array[j] = array[j + 1];
- array[j + 1] = temp;
- flag = true;
- }
- }
- if (!flag) break;// 如果没有发生交换,说明数列已经有序
- }
- }
11.快速改进排序,是一种快速排序的变种。与传统的快速排序不同,它使用分治思想和交换排序(如冒泡排序)的结合。这种算法比传统快速排序更有效,因为它采用分治思想,将大的问题划分成小的子问题,减少了比较次数,提高了排序的效率。对比一下:快速排序是一种分治算法,它采用分而治之的方法来解决问题。步骤如下:1)从数组中选择一个基准元素;2)根据基准元素将数组划分成两半;3)对划分后的子数组使用相同的算法递归排序;4)将排序后的子数组合并为一个有序数组。
以下是完整的能够运行的代码:
- public class ImprovedQuickSort {
-
- public static void improvedQuickSort(int[] array) {
-
- int left = 0;
-
- int right = array.length - 1;
-
- quickSort(array, left, right);
-
- }
-
-
-
- public static void quickSort(int[] array, int left, int right) {
-
- if (left >= right) {
-
- return;
-
- }
-
- // 找出基准元素的位置
-
- int pivotIndex = partition(array, left, right);
-
- // 对左子序列进行排序
-
- quickSort(array, left, pivotIndex - 1);
-
- // 对右子序列进行排序
-
- quickSort(array, pivotIndex + 1, right);
-
- }
-
-
-
- private static int partition(int[] array, int left, int right) {
-
- // 默认基准元素为最左元素
-
- int pivot = array[left];
-
- while (left < right) {
-
- // 从右向左找比基准元素小的元素
-
- while (left < right && array[right] >= pivot) {
-
- right--;
-
- }
-
- array[left] = array[right];
-
- // 从左向右找比基准元素大的元素
-
- while (left < right && array[left] <= pivot) {
-
- left++;
-
- }
-
- array[right] = array[left];
-
- }
-
- // 将基准元素放回正确位置
-
- array[left] = pivot;
-
- return left;
-
- }
-
-
-
- public static void main(String[] args) {
-
- int[] array = new int[]{5,3,9,1,7};
-
- improvedQuickSort(array);
-
- for (int i = 0; i < array.length; i++) {
-
- System.out.print(array[i] + " ");
-
- }
-
- }
-
- }
12.O(NlogN)排序,O(NlogN)排序法是一种常见的排序算法,它是一种基于分治原理的排序算法,由快速排序算法。其操作过程如下:首先找出基准元素pivot,通常为最左边的元素;然后从右向左遍历整个数组,找到第一个比pivot小的元素arr[right],替换位置arr[left];接着,从左往右遍历整个数组,找到第一个比pivot大的元素arr[left],替换位置arr[right];不断地重复该步骤,直至left==right,然后把pivot放回正确位置arr[left];最后递归对左右子序列重复上面的步骤,完成排序。
下面是O(NlogN)排序法的详细代码:
-
- int quickSort(vector<int>&arr, int left, int right)
-
- {
-
- if (left >= right)
-
- return 0;
-
- int i = left;
-
- int j = right;
-
- int pivot = arr[left];
-
- while (i < j)
-
- {
-
- while (i < j && arr[j] >= pivot)
-
- --j;
-
- arr[i] = arr[j];
-
- while (i < j && arr[i] <= pivot)
-
- ++i;
-
- arr[j] = arr[i];
-
- }
-
- arr[i] = pivot;
-
- quickSort(arr, left, i-1);
-
- quickSort(arr, i+1, right);
-
- return 0;
-
- }
1.基数桶排序法是一种采用空间换时间的排序算法。它的基本思想是将数据分成若干(通常是10个)相同大小的桶子,每个桶子中的数据具有相同的基数N,然后对桶子中的每条数据进行比较,并将有序的数据插入另一个链表,最后将该链表转换成数组即为排序后的结果。
- public static void bucketSort(int[] arr)
-
- {
-
- if (arr == null || arr.length < 2)
-
- return;
-
- // 得到数列的最大值
-
- int max = Integer.MIN_VALUE;
-
- for (int i = 0; i < arr.length; i++) {
-
- max = Math.max(max, arr[i]);
-
- }
-
- // 初始化桶
-
- int[] bucket = new int[max + 1];
-
- for (int i = 0; i < bucket.length; i++) {
-
- bucket[i] = 0;
-
- }
-
- // 遍历数组,填充桶
-
- for (int i = 0; i < arr.length; i++) {
-
- bucket[arr[i]]++;
-
- }
-
- // 遍历桶,输出结果
-
- int i = 0;
-
- for (int j = 0; j < bucket.length; j++) {
-
- while(bucket[j]-- > 0) {
-
- arr[i++] = j;
-
- }
-
- }
-
- }
是指当数据量远大于内存容量,无法将所有数据放入内存中进行排序的排序算法。它通过设置一个循环来读取外部文件中的数据,将数据分割为若干小块,并将每一块在内存中排序,之后,再将排序结果写入到一个外部文件中。
外部排序的具体步骤如下:
(1)从外部文件中将数据加载到内存;
(2)对内存中数据进行排序;
(3)将排序结果写入到外部文件;
(4)重复第一步,直到所有的数据都被排序完毕;
(5)将所有已排序的外部文件合并,生成最终的排序结果。以下代码,瑾供参考
外部排序的具体代码实现如下:
- // 将指定的数据块写入到外部文件中
- public static void storeChunk(int[] array, File file) throws IOException {
- try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(
- new FileOutputStream(file)))) {
- for (int d : array) {
- out.writeInt(d);
- }
- }
- }
-
- // 从外部文件中读取指定大小的数据块
- public static int[] loadChunk(File file, int chunkSize) throws IOException {
- try (DataInputStream in = new DataInputStream(new BufferedInputStream(
- new FileInputStream(file)))) {
- int length = (int) (file.length() / 4);
- int[] array = new int[Math.min(length, chunkSize)];
- for (int i = 0; i < array.length; i++) {
- array[i] = in.readInt();
- }
- return array;
- }
- }
-
- // 对外部文件进行排序
- public static void externalSort(File sourceFile, Comparator cmp) throws IOException {
- // 计算文件中总块数
- int chunkSize = 8 * 1024 * 1024 / 4;
- int chunkCount = (int) (sourceFile.length() / chunkSize);
-
- // 加载数据块并对其进行排序
- List<int[]> chunks = new ArrayList<>();
- for (int i = 0; i < chunkCount; i++) {
- int[] array = loadChunk(sourceFile, chunkSize);
- Arrays.sort(array, cmp);
- chunks.add(array);
- }
-
- // 将排序后的数据块一个个合并
- int[] result = chunks.get(0);
- for (int i = 1; i < chunks.size(); i++) {
- result = merge(result, chunks.get(i), cmp);
- }
-
- // 将最终结果写入到原始文件中
- storeChunk(result, sourceFile);
- }
法是指将所有的数据都加载到内存中,然后使用某种算法进行排序。它可以有效避免外部排序法中所需要的I/O操作步骤,从而提升性能和减少时间消耗。
内部排序法的具体步骤如下:
(1)从输入流中读取数据;
(2)将数据加载到内存中;
(3)对内存中的数据进行排序;
(4)将排序结果输出到输出流中。
内部排序的具体代码实现如下:
- // 从输入流中读取数据
-
- public static int[] loadData(DataInputStream in) throws IOException {
-
- int length = in.available() / 4;
-
- int[] array = new int[length];
-
- for (int i = 0; i < length; i++) {
-
- array[i] = in.readInt();
-
- }
-
- return array;
-
- }
-
-
-
- // 将排序结果写入到输出流中
-
- public static void storeData(int[] array, DataOutputStream out) throws IOException {
-
- for (int d : array) {
-
- out.writeInt(d);
-
- }
-
- }
-
-
-
- // 对内存中的数据进行排序
-
- public static void internalSort(int[] array, Comparator cmp) {
-
- Arrays.sort(array, cmp);
-
- }
-
-
-
- // 内部排序总操作
-
- public static void internalSort(DataInputStream in, DataOutputStream out, Comparator cmp) throws IOException {
-
- int[] array = loadData(in);
-
- internalSort(array, cmp);
-
- storeData(array, out);
-
- }
法是一种复杂的排序方法,适用于许多场景,特别是当需要对大量数据进行排序时,它可以极大地提升性能和减少时间消耗。它的原理是把大量数据进行分拆,每一次处理一部分,然后每一部分进行排序,最后再将排好序的数据放到一起。
交错排序的具体步骤如下:
(1)将大量的数据分成N个子集;
(2)每一个子集独立进行排序;
(3)将排好序的N个子集合并成一个有序的数据集合。
交错排序的具体代码实现如下:
- // 将大量数据分成N个子集
- public static <T> List<List<T>> splitData(List<T> data, int subSize) {
- List<List<T>> subs = new ArrayList<>();
- for (int i = 0; i < data.size(); i += subSize) {
- int endIndex = Math.min(i + subSize, data.size());
- subs.add(data.subList(i, endIndex));
- }
- return subs;
- }
-
- // 每一个子集独立进行排序
- public static <T> void internalSort(List<T> sub, Comparator cmp) {
- Collections.sort(sub, cmp);
- }
-
- // 将排好序的N个子集合并成一个有序的数据集合
- public static <T> List<T> mergeSort(List<List<T>> subs, Comparator cmp) {
- List<T> ret = new ArrayList<T>();
- PriorityQueue<Elem<T>> pq = new PriorityQueue<>(cmp);
-
- // 将每一个子集中的第一个元素加入pq中
- for (List<T> sub : subs) {
- if (!sub.isEmpty()) {
- pq.offer(new Elem<>(sub.get(0), sub, 0));
- }
- }
-
- // 迭代处理
- while (!pq.isEmpty()) {
- Elem<T> elem = pq.poll();
- ret.add(elem.val);
- // 将该子集的下一个元素加入pq中
- if (elem.index < elem.list.size() - 1) {
- pq.offer(new Elem<>(elem.list.get(elem.index + 1), elem.list, elem.index + 1));
- }
- }
- return ret;
- }
-
- // 交错排序总操作
- public static <T> List<T> mergeSort(List<T> data, int subSize, Comparator cmp) {
- List<List<T>> subs = splitData(data, subSize);
- for (List<T> sub : subs) {
- internalSort(sub, cmp);
- }
- return mergeSort(subs, cmp);
- }
当然若要对上面的代码进行完善,可以在交错排序函数中增加一个参数,用于设定参与排序的子集的大小,以便更好地兼顾性能与时间。此外,在分组时也可以考虑增加一个把相近数据分到一块的算法,使得排序更有效率。
后言:还有一些较少被使用的排序算法,如希尔伯特曲线排序、梳排序、块排序、序位排序。可以自行查找。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。