-
冒泡排序(Bubble Sort)
- 基本原理 :
- 冒泡排序是一种简单的比较排序算法。它重复地走访要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小(或越大)的元素会经由交换慢慢 "浮" 到数列的顶端(或底端),就像气泡在水中逐渐向上浮起一样。
- 具体步骤 :
- 从数列的第一个元素开始,比较相邻的两个元素。例如,对于一个整数数列
int[] arr = {5, 4, 3, 2, 1}
,首先比较arr[0]
(5)和arr[1]
(4),因为5 > 4
,所以交换它们的位置,数列变为{4, 5, 3, 2, 1}
。 - 接着比较
arr[1]
(5)和arr[2]
(3),交换位置后得到{4, 3, 5, 2, 1}
。按照这样的方式,依次比较相邻的元素,经过第一轮比较后,最大的元素就会 "浮" 到数列的末尾,此时数列变为{4, 3, 2, 1, 5}
。 - 然后进行第二轮比较,从第一个元素开始,重复上述步骤,但是这次只需要比较到倒数第二个元素,因为最大的元素已经在最后位置确定了。经过第二轮比较,第二大的元素会移动到倒数第二个位置。
- 持续这个过程,总共需要进行
n - 1
轮比较(n
是数列的长度),直到整个数列排序完成。
- 从数列的第一个元素开始,比较相邻的两个元素。例如,对于一个整数数列
- 时间复杂度和空间复杂度 :
- 时间复杂度:
- 最坏情况:当数列是倒序排列时,需要进行
n(n - 1)/2
次比较和交换操作,时间复杂度为。例如,对于一个长度为 5 的倒序数列{5, 4, 3, 2, 1}
,第一轮需要比较 4 次,第二轮需要比较 3 次,以此类推,总共需要比较次,符合(时,)的公式。 - 最好情况:当数列已经是正序排列时,只需要进行
n - 1
次比较,没有交换操作,时间复杂度为。 - 平均情况:时间复杂度为,因为在平均情况下,元素的顺序是比较杂乱的,需要进行大量的比较和交换操作。
- 最坏情况:当数列是倒序排列时,需要进行
- 空间复杂度:因为冒泡排序只需要几个额外的变量来进行元素交换,不需要额外的存储空间来存储数据,所以空间复杂度为。
- 时间复杂度:
- 代码示例:
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;
}
}
}
}
} - 基本原理 :
-
插入排序(Insertion Sort)
- 基本原理 :
- 插入排序的基本操作是将一个数据插入到已经排好序的有序数列中,从而得到一个新的、长度加 1 的有序数列。它的工作方式就像人们排序一手扑克牌一样,开始时,左手为空并且桌上的牌面向下。然后,每次从桌上拿起一张牌并将它插入到左手中正确的位置。为了找到这张牌的正确位置,需要将它与手中已有的牌从右到左进行比较。
- 具体步骤 :
- 对于一个数列
int[] arr = {5, 3, 4, 6, 1}
,假设第一个元素arr[0]
(5)已经是有序的。 - 从第二个元素
arr[1]
(3)开始,将它与前面的元素(此时只有arr[0]
)进行比较。因为3 < 5
,所以将 3 插入到 5 的前面,此时数列变为{3, 5, 4, 6, 1}
。 - 接着处理
arr[2]
(4),将 4 与前面已经排序好的元素({3, 5}
)从右到左进行比较。首先与 5 比较,因为4 < 5
,交换它们的位置,得到{3, 4, 5, 6, 1}
。 - 以此类推,每次将一个新元素插入到前面已经排序好的数列中的合适位置,直到整个数列排序完成。
- 对于一个数列
- 时间复杂度和空间复杂度 :
- 时间复杂度:
- 最坏情况:当数列是倒序排列时,每次插入一个元素都需要移动前面的所有元素,总共需要进行
n(n - 1)/2
次比较和移动操作,时间复杂度为。例如,对于数列{5, 4, 3, 2, 1}
,插入 4 时需要移动 1 个元素,插入 3 时需要移动 2 个元素,以此类推,总共需要移动次,符合(时,)的公式。 - 最好情况:当数列已经是正序排列时,只需要进行
n - 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;
}
}
} - 基本原理 :
-
选择排序(Selection Sort)
- 基本原理 :
- 选择排序的基本思想是在未排序的数列中找到最小(或最大)的元素,将其与数列的第一个(或最后一个)未排序元素交换位置。然后,在剩下的未排序元素中继续这个操作,直到所有元素都排序完成。
- 具体步骤 :
- 对于一个数列
int[] arr = {5, 4, 3, 2, 1}
,首先在整个数列中找到最小的元素,即 1。然后将 1 与第一个元素 5 交换位置,此时数列变为{1, 4, 3, 2, 5}
。 - 接着在剩下的未排序元素
{4, 3, 2, 5}
中找到最小的元素,即 2。将 2 与第二个元素 4 交换位置,得到{1, 2, 3, 4, 5}
。 - 按照这样的方式,每次从剩余的未排序元素中选择最小的元素,并将其放置到合适的位置,直到整个数列排序完成。
- 对于一个数列
- 时间复杂度和空间复杂度 :
- 时间复杂度:
- 无论数列的初始顺序如何,选择排序都需要进行 `n (n - 1)/2次比较操作来找到最小(或最大)元素,时间复杂度为O(n^2)$。例如,对于一个长度为5的数列,第一轮需要比较4次来找到最小元素,第二轮需要比较3次来找到剩余元素中的最小元素,以此类推,总共需要比较次,符合(时,5×(5 - 1)/2 = 10)的公式。
- 交换操作的次数最多为
n - 1
次,因为每次交换都将一个元素放置到最终位置。
- 空间复杂度:选择排序只需要几个额外的变量来进行元素比较和交换,不需要额外的存储空间来存储数据,所以空间复杂度为。
- 时间复杂度:
- 代码示例:
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;
}
}
} - 基本原理 :
-
快速排序(Quick Sort)
- 基本原理 :
- 快速排序是一种分治算法。它的基本思想是选择一个基准元素(pivot),通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比基准元素小,另一部分的所有数据都比基准元素大。然后,分别对这两部分数据进行快速排序,整个排序过程可以递归地进行,直到整个数列排序完成。
- 具体步骤 :
- 例如,对于一个数列
int[] arr = {5, 2, 8, 1, 9}
,选择第一个元素 5 作为基准元素(pivot)。 - 设置两个指针,一个从数列的左边开始(
left
),一个从数列的右边开始(right
)。 - 从右向左移动
right
指针,找到第一个小于基准元素的元素,即 1。同时,从左向右移动left
指针,找到第一个大于基准元素的元素,即 8。 - 交换 1 和 8 的位置,此时数列变为
{5, 2, 1, 8, 9}
。 - 继续移动指针,直到
left
和right
相遇。此时,将基准元素 5 与left
指针指向的元素(1)交换位置,得到{1, 2, 5, 8, 9}
。这样,就将数列分成了两部分,左边部分{1, 2}
都小于 5,右边部分{8, 9}
都大于 5。 - 然后对左右两部分
{1, 2}
和{8, 9}
分别进行快速排序,直到整个数列排序完成。
- 例如,对于一个数列
- 时间复杂度和空间复杂度 :
- 时间复杂度:
- 平均情况:时间复杂度为。这是因为每次划分可以将数列分为大致相等的两部分,递归的深度为,每层需要的时间来划分。例如,对于一个长度为 8 的数列,第一次划分后得到两个长度约为 4 的子数列,第二次划分后得到四个长度约为 2 的子数列,以此类推,划分的次数大约为次,每次划分需要比较和移动元素,时间复杂度约为。
- 最坏情况:当数列已经是正序或倒序排列,并且每次选择的基准元素都是最大或最小元素时,快速排序退化为冒泡排序,时间复杂度为。
- 空间复杂度:
- 最坏情况:需要的栈空间来存储递归调用的信息,因为在最坏情况下,递归深度为
n
。 - 平均情况:空间复杂度为,因为在平均情况下,递归深度为。
- 最坏情况:需要的栈空间来存储递归调用的信息,因为在最坏情况下,递归深度为
- 时间复杂度:
- 代码示例:
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);
}
}
private static int partition(int[] arr, int low, int high) {
int pivot = arr[low];
int i = low + 1;
int j = high;
while (true) {
while (i <= j && arr[i] <= pivot) {
i++;
}
while (i <= j && arr[j] > pivot) {
j--;
}
if (i > j) {
break;
}
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
int temp = arr[low];
arr[low] = arr[j];
arr[j] = temp;
return j;
}
} - 基本原理 :
-
归并排序(Merge Sort)
- 基本原理 :
- 归并排序也是一种分治算法。它的基本思想是将一个数列分成两个子数列,对每个子数列进行排序,然后将排序好的子数列合并成一个有序的数列。这个过程可以递归地进行,直到子数列的长度为 1,此时数列已经排序完成。
- 具体步骤 :
- 例如,对于一个数列
int[] arr = {5, 3, 8, 1, 9}
。 - 首先将数列分成两个子数列,即
{5, 3}
和{8, 1, 9}
。 - 继续对这两个子数列进行划分,得到
{5}
、{3}
、{8}
、{1}
、{9}
,此时子数列的长度为 1,已经是有序的。 - 然后开始合并过程,先合并
{5}
和{3}
,得到{3, 5}
。接着合并{8}
和{1}
,得到{1, 8}
。再合并{1, 8}
和{9}
,得到{1, 8, 9}
。 - 最后合并
{3, 5}
和{1, 8, 9}
,得到{1, 3, 5, 8, 9}
,此时整个数列排序完成。
- 例如,对于一个数列
- 时间复杂度和空间复杂度 :
- 时间复杂度:
- 无论数列的初始顺序如何,归并排序的时间复杂度都是。因为每次划分需要的时间,总共需要划分次,每次合并需要的时间。例如,对于一个长度为 8 的数列,第一次划分得到两个长度为 4 的子数列,第二次划分得到四个长度为 2 的子数列,以此类推,划分次数为次。每次合并两个子数列时,需要比较和移动元素,时间复杂度为。
- 空间复杂度:归并排序需要一个临时数组来存储合并后的元素,所以空间复杂度为。
- 时间复杂度:
- 代码示例:
public class MergeSort {
public static void mergeSort(int[] arr) {
if (arr.length > 1) {
int mid = arr.length / 2;
int[] left = new int[mid];
int[] right = new int[arr.length - mid];
for (int i = 0; i < mid; i++) {
left[i] = arr[i];
}
for (int i = mid; i < arr.length; i++) {
right[i - mid] = arr[i];
}
mergeSort(left);
mergeSort(right);
merge(arr, left, right);
}
}
private static void merge(int[] arr, int[] left, int[] right) {
int i = 0, j = 0, k = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
arr[k++] = left[i++];
} else {
arr[k++] = right[j++];
}
}
while (i < left.length) {
arr[k++] = left[i++];
}
while (j < right.length) {
arr[k++] = right[j++];
}
}
} - 基本原理 :
java的几种排序算法(详细)
肘击鸣的百k路2024-12-05 20:15
相关推荐
m0_748255022 分钟前
头歌答案--爬虫实战小猿_0010 分钟前
C语言程序设计十大排序—插入排序小白的一叶扁舟21 分钟前
深入剖析 JVM 内存模型sjsjsbbsbsn29 分钟前
基于注解实现去重表消息防止重复消费苹果醋330 分钟前
golang 编程规范 - Effective Go 中文chengpei1471 小时前
实现一个自己的spring-boot-starter,基于SQL生成HTTP接口等一场春雨2 小时前
Java设计模式 十二 享元模式 (Flyweight Pattern)熊文豪2 小时前
深入解析人工智能中的协同过滤算法及其在推荐系统中的应用与优化努力搬砖的程序媛儿4 小时前
uniapp悬浮可拖拽按钮上海拔俗网络4 小时前
“AI开放式目标检测系统:开启智能识别新时代