代碼原創,引用他人模型演示
一、插入排序
直接插入插排的基本思想是:當插入第i(i >= 1)時,前面的元素已經排好序。
時間複雜度爲O(n^2)
73-插入排序——直接插入排序 - 專注於linux,網絡安全 - CSDN博客
https://blog.csdn.net/qq_35733751/article/details/81713061
(動圖做的真形象)
public int[] insert(int[] arr) {
int[] a = arr;
//只有一個元素
if (a.length <= 1)
return null;
//超過一個元素
for (int i = 1; i < a.length; i++) {
int b = a[i];
int j = i - 1;
//相比較和將較大的數往後放
while (j >= 0 && b < a[j]) {
a[j + 1] = a[j];
j--;
}
//大於當前位置的最大數,固定位置
a[j + 1] = b;
}
return a;
}
二、希爾排序
算法解釋如下:
希爾排序--簡單易懂圖解 - 祥哥的說 - CSDN博客
https://blog.csdn.net/qq_39207948/article/details/80006224
(吐槽:這倆和尚除了唸經真的啥都會)
public void shell(int[] arr){
int N=arr.length;
//確定增量
for (int gap=N/2;gap>0;gap/=2){
//分組,依次進行插入排序
for (int i=gap;i<N;i++){
insertI(arr,gap,i);
}
}
}
//插入排序
public void insertI(int[] arr,int gap,int i){
int tmp=arr[i];
//記錄排序後的位置
int j=i-gap;
//對已經分組的元素進行插入排序
while(j>=0&&tmp<arr[j]){
arr[j+gap]=arr[j];
j-=gap;
}
arr[j+gap]=tmp;
}
三、冒泡排序
冒泡排序是一種比較簡單的排序算法(找最小值或最大值),循環所有元素,依次比較相鄰的兩個元素,如果小於(大於)就交換,直至沒有元素交換,完成排序。
時間複雜度爲O(n^2)
寫文章-CSDN博客
https://mp.csdn.net/mdeditor/103040244#
public int[] foam(int[] arr) {
int[] a = arr;
if (a.length <= 1)
return null;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a.length - i - 1; j++) {
//相鄰位置互相比較,將最大值放在最後
if (a[j] > a[j + 1]) {
int b = a[j];
a[j] = a[j + 1];
a[j + 1] = b;
}
}
}
return a;
}
四、快速排序
這個解釋的很詳細且生動了
快速排序—(面試碰到過好幾次) - nrsc - CSDN博客
https://blog.csdn.net/nrsc272420199/article/details/82587933
根據個人理解寫的代碼
/*
* main中傳參
* quick(arr, 0, arr.length - 1);
* */
public void quick(int[] arr, int low, int high) {
if (arr.length<=1)
return;
int[] a = arr;
//首
int i = low;
//尾
int j = high;
//退出條件
if (low > high)
return;
//基值
int x = a[low];
//low!=high
while (i < j) {
//從右到左找到大於基值的數
while (i < j & a[j] >= x) {
j--;
}
a[i] = a[j];
//從左到右找到小於基值的數
while (i < j && a[i] < x) {
i++;
}
a[j] = a[i];
}
//i=j;賦中值(很關鍵,不能忘)
a[i] = x;
//low=high
quick(a, low, i - 1);
quick(a, i + 1, high);
}
五、選擇排序
工作原理是每一次從待排序的數據元素中選出最小(或最大)的一個元素,存放在序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。以此類推,直到全部待排序的數據元素排完。
選擇排序是不穩定的排序方法。
原因:在一趟選擇,如果一個元素比當前元素小,而該小的元素又出現在一個和當前元素相等的元素後面,那麼交換後穩定性就被破壞了。
如:序列5 8 5 2 9,我們知道第一遍選擇第1個元素5會和2交換,那麼原序列中兩個5的相對前後順序被破壞了,所以選擇排序是一個不穩定的排序算法。
此處多寫一個遞歸的例子
public void select(int[] arr, int k) {
if (arr.length<=1)
return;
/*
* 利用遞歸循環或者for循環
* */
//遞歸
//退出條件
if (k == arr.length - 1) return;
int a = arr[k];
int b = 0;
int c = arr[k];
//找到待排序元素的最小值,放在待排序列表的首位
for (int i = k; i < arr.length - 1; i++) {
if (a > arr[i + 1]) {
a = arr[i + 1];
b = i + 1;
}
}
//避免本身就是最大值
if (b != 0)
arr[b] = c;
arr[k] = a;
k++;
select(arr, k);
}
for循環解決
public void select(int[] arr, int k) {
for (int i = 0; i < arr.length - 1; i++) {
int tmp = i;
//找到最大值
for (int j = i + 1; j < arr.length; j++) {
if (arr[tmp] > arr[j]) {
tmp = j;
}
}
//避免本身就是最大值
if (tmp != i) {
//兩兩互換位置
int a = arr[tmp];
arr[tmp] = arr[i];
arr[i] = a;
}
}
}
六、歸併排序
歸併排序_嗶哩嗶哩 (゜-゜)つロ 乾杯~-bilibili
https://www.bilibili.com/video/av9982752?from=search&seid=4684025026002002014
(視頻講的很細緻)
個人理解:
歸併是對分治的兩個組合元素進行比較和排序
主要實現方法是:
利用中值,將分治的左右兩個元素分別存在在左右數組Left和Right,用i,j,k表示Left,Right,arr的指針,將兩個數組的最小值放入arr數組當中(第一次分治的時候只有兩個元素,因此,當前元素合併之後,一定是排序好的),根據分治的遞歸,完成排序的工作.
附上完整代碼
//歸併排序
public void merge(int[] arr, int L, int M, int R) {
//利用中值M,將兩組數分割
int Left_arr[] = new int[M - L];
int Right_arr[] = new int[R - M + 1];
//Left
for (int i = L; i < M; i++) {
Left_arr[i - L] = arr[i];
}
//Right
for (int i = M; i <= R; i++) {
Right_arr[i - M] = arr[i];
}
//i代表Left,j代表Right,k代表arr
int i = 0, j = 0, k = L;
//歸併
while (i < Left_arr.length && j < Right_arr.length) {
if (Left_arr[i] <= Right_arr[j]) {
arr[k] = Left_arr[i];
i++;
k++;
} else {
arr[k] = Right_arr[j];
j++;
k++;
}
}
//左側存在剩餘元素
while (i < Left_arr.length) {
arr[k] = Left_arr[i];
i++;
k++;
}
//右側存在剩餘元素
while (j < Right_arr.length) {
arr[k] = Right_arr[j];
j++;
k++;
}
}
public void merge_sort(int[] arr, int L, int R) {
//退出條件,只有一個元素
if (L == R)
return;
//求中值
int M = (R + L) / 2;
//左 第一次執行時,L=0,R=1,M=0
merge_sort(arr, L, M);
//右 第一次執行時,L=0,R=1,M=0
merge_sort(arr, M + 1, R);
//左右歸併
merge(arr, L, M + 1, R);
}