文章目录
1. 冒泡排序
1.1 排序原理
- 比较相邻的元素。如果前一个元素比后一个元素大,就交换这两个元素的位置。
- 对每一对相邻元素做同样的工作,从开始第一对元素到结尾的最后一对元素。最终最后位置的元素就是最大值。
- 需要注意的是,每次比较的次数为为排序数组长度减一
1.2 代码实现
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int[] a ={1,3,5,7,2,6};
Bubble(a);
System.out.println(Arrays.toString(a));
}
//比如六个数,第一次比较5次,第二次比较4次。。。
private static void Bubble(int[] a) {
for(int i=a.length-1;i>0;i--){
for(int j = 0;j<i;j++){
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
}
}
时间复杂度O(N^2)
2. 选择排序
2.1 排序原理
1.每一次遍历的过程中,都假定第一个索引处的元素是最小值,和其他索引处的值依次进行比较,如果当前索引处的值大于其他某个索引处的值,则假定其他某个索引出的值为最小值,最后可以找到最小值所在的索引
2.交换第一个索引处和最小值所在的索引处的值
2.2 代码实现
import java.util.Arrays;
public class SelectSort {
public static void main(String[] args) {
int[] a = {1,3,2,5,7,4};
Select(a);
System.out.println(Arrays.toString(a));
}
//假设第一个位置就是最小元素,遍历数组,寻找最小元素,找到就将第一个位置元素与最小元素交换索引
private static void Select(int[] a) {
for(int i = 0;i<a.length-1;i++){
//假定本次遍历,最小值所在的索引是i
int index = i;
for(int j = i+1;j<a.length;j++){
if(a[j]<a[index]){
//交换最小值所在的索引
index = j;
}
}
//每次循环的i都是未排序的第一个
int temp = a[i];
a[i] = a[index];
a[index] = temp;
}
}
}
时间复杂度O(N^2)
3. 插入排序
3.1 排序原理
1.把所有的元素分为两组,已经排序的和未排序的;
2.找到未排序的组中的第一个元素,向已经排序的组中进行插入;
3.倒叙遍历已经排序的元素,依次和待插入的元素进行比较,直到找到一个元素小于等于待插入元素,那么就把待插入元素放到这个位置,其他的元素向后移动一位;
3.2 代码实现
import java.util.Arrays;
public class InsertSort {
public static void main(String[] args) {
int [] a = {1,4,3,6,2,5};
Insert(a);
System.out.println(Arrays.toString(a));
}
//默认第一个元素有序,从第二个开始,往前比较,如果比他大,则交换位置
private static void Insert(int[] a) {
//由于默认认为第一个是有序的,则从第二个元素开始比较,因此循环从1开始
for(int i = 1;i<a.length;i++){
for(int j = i;j>0;j--){
if(a[j]<a[j-1]){
int temp = a[j];
a[j] = a[j-1];
a[j-1] = temp;
}
}
}
}
}
时间复杂度O(N^2)
4. 归并排序
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
4.1 排序原理
1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是1为止。
2.将相邻的两个子组进行合并成一个有序的大组;
3.不断的重复步骤2,直到最终只有一个组为止。
如何治呢?我们看下一张图
4.2 代码实现
import java.util.Arrays;
public class mergeSort {
public static void main(String[] args) {
int[] a = {1, 3, 2, 5, 4, 6, 8, 7};
int[] temp = new int[a.length];
int left = 0;
int right = a.length-1;
MergeSort(a,left,right,temp);
System.out.println(Arrays.toString(a));
}
public static void MergeSort(int[] arr,int left,int right,int[] temp){
if(left<right){
int mid = (left+right)/2;
//分
MergeSort(arr,left,mid,temp);
MergeSort(arr,mid+1,right,temp);
//治
Merge(arr,left,mid,right,temp);
}
}
//如何治:分三步
public static void Merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left;
int j = mid + 1;
int t = 0;
//1. 先把左右两边的有序数据按规则填到temp数组,直到有一方填完为止
while (i <= mid && j <= right) {
if (arr[i] < arr[j]) {
temp[t] = arr[i];
t++;
i++;
} else {
temp[t] = arr[j];
t++;
j++;
}
}
//2. 把有剩余数据一边的剩余数据拷贝到临时数组
while (i <= mid) {
temp[t] = arr[i];
t++;
i++;
}
while (j <= right) {
temp[t] = arr[j];
t++;
j++;
}
//3. 把temp数组拷贝回arr数组,不是每次都拷贝所有
t = 0;
int tempLeft = left;
while (tempLeft <= right) {
arr[tempLeft] = temp[t];
tempLeft++;
t++;
}
}
}
时间复杂度O(nlogn),代价就是用空间换时间。
5. 排序算法稳定性分析
冒泡排序:
只有当arr[i]>arr[i+1]的时候,才会交换元素的位置,而相等的时候并不交换位置,所以冒泡排序是一种稳定排序算法。
选择排序:
选择排序是给每个位置选择当前元素最小的,例如有数据{5(1),8 ,5(2), 2, 9 },第一遍选择到的最小元素为2,所以5(1)会和2进行交换位置,此时5(1)到了5(2)后面,破坏了稳定性,所以选择排序是一种不稳定的排序算法。
插入排序:
比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相等的,那么把要插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
归并排序:
归并排序在归并的过程中,只有arr[i]<arr[i+1]的时候才会交换位置,如果两个元素相等则不会交换位置,所以它并不会破坏稳定性,归并排序是稳定的。