数据结构之二(排序算法)

1、冒泡排序(Bubble Sort)

冒泡排序是一种简单的排序算法。它重复地比较相邻的两个元素,如果顺序不正确就交换它们,直到整个数组排序完成。

以下是冒泡排序的基本步骤:

  1. 从数组的第一个元素开始,比较该元素和下一个元素的大小。
  2. 如果顺序不正确(例如,当前元素大于下一个元素),则交换它们的位置。
  3. 继续向下比较相邻元素,重复上述步骤,直到最后一个元素。
  4. 重复以上步骤,每次循环都能将未排序部分的最大元素移动到末尾。
  5. 重复上述步骤,直到整个数组排序完成。
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]) {
                    // 交换元素
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
}

2、选择排序(Selection Sort)

选择排序是一种简单的排序算法,它每次从未排序部分选择最小(或最大)的元素,并将其放到已排序部分的末尾。

以下是选择排序的基本步骤:

  1. 在未排序部分找到最小(或最大)的元素。
  2. 将最小(或最大)的元素与未排序部分的第一个元素交换位置,将该元素放到已排序部分的末尾。
  3. 接下来,将未排序部分的起始位置向后移动一位,缩小未排序部分的范围。
  4. 重复上述步骤,直到未排序部分为空。
public class SelectionSort {
    public static void selectionSort(int[] arr) {
        int n = arr.length;

        for (int i = 0; i < n - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < n; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            // 交换元素
            int temp = arr[minIndex];
            arr[minIndex] = arr[i];
            arr[i] = temp;
        }
    }
}

3、插入排序(Insertion Sort)

插入排序是一种简单的排序算法,它通过构建有序序列,对未排序的部分逐个进行插入操作。

以下是插入排序的基本步骤:

  1. 假设第一个元素已经被排序(可以看作只有一个元素的有序序列)。
  2. 取出下一个未排序的元素,在已排序的序列中从后向前扫描。
  3. 如果该元素(已排序)大于新元素,则将该元素移到下一位置。
  4. 重复步骤3,直到找到已排序的元素小于或等于新元素的位置。
  5. 将新元素插入到该位置。
  6. 重复步骤2~5,直到所有元素都被排序。
public class SelectionSort {
    public static void selectionSort(int[] arr) {
        int n = arr.length;

        for (int i = 0; i < n - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < n; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            // 交换元素
            int temp = arr[minIndex];
            arr[minIndex] = arr[i];
            arr[i] = temp;
        }
    }
}

总结:

上面讲的三种排序,冒泡、选择、插入用大 O 表示法都需要 O(N2) 时间级别。一般不会选择冒泡排序,虽然冒泡排序书写是最简单的,但是平均性能是没有选择排序和插入排序好的。

4、快速排序

快速排序(Quick Sort)是一种高效的排序算法,它采用了分治的思想,通过递归地将数据分解成较小的部分来实现排序。

以下是快速排序的基本步骤:

  1. 选择一个基准元素(通常是数组中的第一个元素、最后一个元素或者中间元素)。
  2. 将小于基准元素的元素移动到基准元素的左边,将大于基准元素的元素移动到右边,这个过程称为分区(Partition)操作。
  3. 分别对基准元素左右两边的子序列进行递归排序。
public class QuickSort {
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            int pivotIndex = partition(arr, low, high);
            quickSort(arr, low, pivotIndex - 1);
            quickSort(arr, pivotIndex + 1, high);
        }
    }

    public 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;
    }

}

5、归并排序(Merge Sort)

归并排序(Merge Sort)是一种稳定的排序算法,它也采用了分治的思想,将待排序的序列分成若干个子序列,每个子序列都是有序的。然后再将子序列合并成一个整体有序序列。

以下是归并排序的基本步骤:

  1. 将待排序的序列不断地二分,直到无法继续划分。
  2. 对每个子序列进行排序,可以使用递归实现排序操作。
  3. 合并相邻的两个子序列,得到新的有序序列,重复上述操作,直到最后排序完成。
public class MergeSort {
    public static void mergeSort(int[] arr, int left, int right) {
        if (left < right) {
            int mid = (left + right) / 2;
            mergeSort(arr, left, mid);
            mergeSort(arr, mid + 1, right);
            merge(arr, left, mid, 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++];
        }
        for (int m = 0; m < temp.length; m++) {
            arr[left + m] = temp[m];
        }
    }
}

6、堆排序(Heap Sort)

堆排序(Heap Sort)是一种利用堆的数据结构来进行排序的算法,它利用了最大堆或最小堆这种特殊的数据结构来完成排序过程。

以下是堆排序的基本步骤:

  1. 将待排序的序列构建成一个最大堆(或最小堆)。
  2. 交换堆顶元素和堆中最后一个元素,并将堆的大小减一,然后对剩下的元素重新进行堆调整,使其满足堆的性质。
  3. 重复步骤2,直到堆的大小为1,排序完成。
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);
        }
    }

    public static void heapify(int[] arr, int n, int i) {
        int largest = i;
        int left = 2 * i + 1;
        int right = 2 * i + 2;

        if (left < n && arr[left] > arr[largest]) {
            largest = left;
        }

        if (right < n && arr[right] > arr[largest]) {
            largest = right;
        }

        if (largest != i) {
            int temp = arr[i];
            arr[i] = arr[largest];
            arr[largest] = temp;
            heapify(arr, n, largest);
        }
    }
}

7、计数排序(Counting Sort)

计数排序(Counting Sort)是一种非比较排序算法,它通过确定每个元素在排序后的序列中的位置来进行排序。计数排序适用于待排序元素范围较小且已知的情况。

以下是计数排序的基本步骤:

  1. 找出待排序序列中的最大值,并创建一个计数数组 count,长度为最大值加一。
  2. 遍历待排序序列,统计每个元素出现的次数,并将结果存储在计数数组 count 中对应元素的位置上。
  3. 对计数数组 count 进行累加操作,得到每个元素在排序后序列中的最终位置。
  4. 创建一个与待排序序列长度相同的辅助数组 result
  5. 从后向前遍历待排序序列,根据元素的计数值和计数数组中的位置信息,将元素放入辅助数组 result 中对应的位置上。
  6. 将辅助数组 result 的内容复制回原始的待排序序列。
public class CountingSort {
    public static void countingSort(int[] arr) {
        int n = arr.length;

        // 找出待排序序列中的最大值
        int max = arr[0];
        for (int i = 1; i < n; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }

        // 创建计数数组,长度为最大值加一
        int[] count = new int[max + 1];

        // 统计每个元素出现的次数
        for (int i = 0; i < n; i++) {
            count[arr[i]]++;
        }

        // 计算每个元素在排序后序列中的最终位置
        for (int i = 1; i <= max; i++) {
            count[i] += count[i - 1];
        }

        // 创建辅助数组
        int[] result = new int[n];

        // 根据计数值和计数数组中的位置信息,将元素放入辅助数组中
        for (int i = n - 1; i >= 0; i--) {
            result[count[arr[i]] - 1] = arr[i];
            count[arr[i]]--;
        }

        // 将辅助数组的内容复制回原始的待排序序列
        for (int i = 0; i < n; i++) {
            arr[i] = result[i];
        }
    }
}

8、桶排序(Bucket Sort)

桶排序(Bucket Sort)是一种排序算法,它将待排序数据分割成若干个有序的桶(或称为容器),每个桶内的数据进行排序,最后将桶中的数据依次取出,即可得到有序序列。

以下是桶排序的基本步骤:

  1. 确定桶的数量和范围。根据待排序数据的特点,确定适当的桶的数量和每个桶的范围。
  2. 将待排序数据分配到对应的桶中。遍历待排序数据,根据每个数据的大小,将其放入对应的桶中。
  3. 对每个桶中的数据进行排序。可以使用其他排序算法,如插入排序、快速排序等,在每个桶内部进行排序。
  4. 按顺序将每个桶中的数据取出。将排序后的桶中数据按顺序取出,组成最终的有序序列。
import java.util.ArrayList;
import java.util.Collections;

public class BucketSort {
    public static void bucketSort(int[] arr, int bucketSize) {
        if (arr.length <= 1) {
            return;
        }

        // 确定桶的数量和范围
        int minValue = arr[0];
        int maxValue = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] < minValue) {
                minValue = arr[i];
            } else if (arr[i] > maxValue) {
                maxValue = arr[i];
            }
        }

        int bucketCount = (maxValue - minValue) / bucketSize + 1;
        ArrayList<ArrayList<Integer>> buckets = new ArrayList<>(bucketCount);
        for (int i = 0; i < bucketCount; i++) {
            buckets.add(new ArrayList<>());
        }

        // 将待排序数据分配到对应的桶中
        for (int i = 0; i < arr.length; i++) {
            int bucketIndex = (arr[i] - minValue) / bucketSize;
            buckets.get(bucketIndex).add(arr[i]);
        }

        // 对每个桶中的数据进行排序
        int currentIndex = 0;
        for (int i = 0; i < bucketCount; i++) {
            ArrayList<Integer> bucket = buckets.get(i);
            Collections.sort(bucket);
            for (int j = 0; j < bucket.size(); j++) {
                arr[currentIndex++] = bucket.get(j);
            }
        }
    }
}

9、基数排序(Radix Sort)

基数排序(Radix Sort)是一种非比较型的排序算法,它将整数按照位数进行排序。基数排序可以分为 LSD(Least Significant Digit)和 MSD(Most Significant Digit)两种方式。

以下是基数排序(LSD方式)的基本步骤:

  1. 确定待排序整数的最大位数,并按照位数创建 10 个桶(0-9)。
  2. 从整数的最低位开始,按照每个位上的数字将整数放入对应的桶中。
  3. 按照桶的顺序依次取出每个整数,组成新的序列。
  4. 重复第 2 步和第 3 步,直到所有位都被处理。
import java.util.Arrays;
public class RadixSort {
    public static void radixSort(int[] arr) {
        if (arr.length <= 1) {
            return;
        }

        // 找到数组中的最大值
        int max = arr[0];
        for (int value : arr) {
            if (value > max) {
                max = value;
            }
        }

        int exp = 1;
        int n = arr.length;
        int[] temp = new int[n];
        while (max / exp > 0) {
            int[] count = new int[10];

            // 统计每个桶中的元素个数
            for (int value : arr) {
                count[(value / exp) % 10]++;
            }

            // 将 count 转换为当前位的实际位置
            for (int i = 1; i < 10; i++) {
                count[i] += count[i - 1];
            }

            // 根据当前位的值将数据存储到临时数组 temp 中
            for (int i = n - 1; i >= 0; i--) {
                temp[count[(arr[i] / exp) % 10] - 1] = arr[i];
                count[(arr[i] / exp) % 10]--;
            }

            // 将临时数组的内容复制回原始数组
            System.arraycopy(temp, 0, arr, 0, n);

            exp *= 10;
        }
    }
}

总结

性能比较

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AngleoLong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值