冒泡排序
(1)原理:
1、从第一个数据开始,与第二个数据相比较,如果第二个数据小于第一个数据,则交换两个数据的位置。
2、指针由第一个数据移向第二个数据,第二个数据与第三个数据相比较,如果第三个数据小于第二个数据,则交换两个数据的位置。
3、依此类推,完成第一轮排序。第一轮排序结束后,最大的元素被移到了最右面。
4、依照上面的过程进行第二轮排序,将第二大的排在倒数第二的位置。
5、重复上述过程,没排完一轮,比较次数就减少一次。
(2)例子:
待排序数据:7, 6, 9, 8, 5,1
第一轮排序过程:
指针先指向7,7和6比较,6<7,交换6和7的位置,结果为:6,7,9,8,5,1
指针指向第二个元素7,7和9比较,9>7,不用交换位置,结果仍为:6,7,9,8,5,1
指针指向第三个元素9,比较9和8,8<9,交换8和9的位置,结果为:6,7,8,9,5,1
指针指向第四个元素9,比较9和5,5<9,交换5和9,结果为:6,7,8,5,9,1
指针指向第五个元素9,比较9和1,1<9,交换1和9的位置,结果为6,7,8,5,1,9
第一轮排序结束后,最大的数字9被移到了最右边。
进行第二轮排序,过程同上,只是由于最大的9已经放在最右边了,因此不用在比较9了,少了一次比较,第二轮结束的结果为:6,7,5,1,8,9
第三轮结果:6,5,1,7,8,9
第四轮比较结果:5,1,6,7,8,9
第五轮比较结果:1,5,6,7,8,9
最终排序结果为:1,5,6,7,8,9,由上可知N个数据排序,需要进行N-1轮排序;第i轮排序需要的比较次数为N-i次。
3)编码思路:
需要两层循环,第一层循环i表示排序的轮数,第二层循环j表示比较的次数。
第一个元素与第二个元素比较,第二个再与第三个相比…每一次比较都需要把大的元素往后移,如果一次循环下来没有交换过元素,则证明该数组是有序的,可以直接退出。
package com.yzh.day1;
import java.util.Arrays;
/**
* @author yaozh
* @date 2023/2/17 9:45
* 冒泡排序
*/
public class demo6 {
public static void main(String[] args) {
int[] array = new int[]{1, 6, 5, 6, 4, 2, 7, 3};
//1,-8,6,4,2,6,3,7 第一次冒泡 7次循环
//-8,1,4,2,6,3,6 第二次冒泡
//-8,1,2,4,6,3
//-8,1,2,4,3,
//-8,1,2,3
//-8,1,2
//-8,1
System.out.println(Arrays.toString(bubbleSort(array)));
}
public static int[] bubbleSort(int[] array) {
//冒泡次数
for (int i = 0; i < array.length - 1; i++) {
boolean flag=true;
//冒泡步骤
for (int j = 0; j < array.length - i - 1; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
flag=false;
}
}
if (flag){
break;
}
}
return array;
}
}
选择排序
原理:
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。重复第二步,直到所有元素均排序完毕。
思想:
刚开始随便选择一个元素,定义一个下标指向这个元素,作为待比较的对象(key),然后将其他元素一次与这个key相比,如果找到比key小(或者大)的元素,则将指向这个元素的下标移动到新元素位置,然后再拿后面没比较过的元素与新的key比较,一直这这样比较完一次,就能找到最小或者最大的第一个元素,然后将其与数组第一个元素交换位置。然后重复上面步骤。
示例
/**
*
* @author yaozh
* @date 2023/2/17 17:15
*选择排序
*/
public class demo7 {
public static void main(String[] args) {
int[] array = new int[]{1, 6, -8, 6, 4, 2, 7, 3};
//-8,6,1,4,2,6,3,7 第一次排序 经过第一轮比较,指针指向最小的数为-8,然后i为0,-8的小标不等于i,所以交换他们两个的位置
//-8,1,6,4,2,6,3,7 第二次排序 指针一开始指向6,i=1,然后同上步骤一样
//-8,1,2,4,6,6,3,7
//-8,1,2,3,6,6,4,7
//-8,1,2,3,4,6,6,7
//-8,1,2,3,4,6,6,7
//-8,1,2,3,4,6,6,7
System.out.println(Arrays.toString(selectionSort(array)));
}
public static int[] selectionSort(int[] array){
for (int i=0;i<array.length-1;i++){
int minIndex=i;
for (int j=i+1;j<array.length;j++){
if (array[minIndex]>array[j]){
minIndex=j;
}
}
if (minIndex!=i){
int temp=array[i];
array[i]=array[minIndex];
array[minIndex]=temp;
}
}
return array;
}
}
选择排序总结:
N个元素需要排序N-1轮;
第i轮需要比较N-i次;
N个元素排序,需要比较n(n-1)/2次;
选择排序的算法复杂度仍为O(n*n);
相比于冒泡排序,选择排序的交换次数大大减少,因此速度要快于冒泡排序
插入排序
(1)原理:
- 1、将指针指向某个元素,假设该元素左侧的元素全部有序,将该元素抽取出来,然后按照从右往左的顺序分别与其左边的元素比较,遇到比其大的元素便将元素右移,直到找到比该元素小的元素或者找到最左面发现其左侧的元素都比它大,停止;
- 2、此时会出现一个空位,将该元素放入到空位中,此时该元素左侧的元素都比它小,右侧的元素都比它大;
- 3、指针向后移动一位,重复上述过程。每操作一轮,左侧有序元素都增加一个,右侧无序元素都减少一个。
(2)例子:
待比较数据:7, 6, 9, 8, 5,1 - 第一轮:指针指向第二个元素6,假设6左面的元素为有序的,将6抽离出来,形成7,,9,8,5,1,从7开始,6和7比较,发现7>6。将7右移,形成,7,9,8,5,1,6插入到7前面的空位,结果:6,7,9,8,5,1
- 第二轮:指针指向第三个元素9,此时其左面的元素6,7为有序的,将9抽离出来,形成6,7,_,8,5,1,从7开始,依次与9比较,发现9左侧的元素都比9小,于是无需移动,把9放到空位中,结果仍为:6,7,9,8,5,1
- 第三轮:指针指向第四个元素8,此时其左面的元素6,7,9为有序的,将8抽离出来,形成6,7,9,,5,1,从9开始,依次与8比较,发现8<9,将9向后移,形成6,7,,9,5,1,8插入到空位中,结果为:6,7,8,9,5,1
- 第四轮:指针指向第五个元素5,此时其左面的元素6,7,8,9为有序的,将5抽离出来,形成6,7,8,9,,1,从9开始依次与5比较,发现5比其左侧所有元素都小,5左侧元素全部向右移动,形成,6,7,8,9,1,将5放入空位,结果5,6,7,8,9,1。
- 第五轮:同上,1被移到最左面,最后结果:1,5,6,7,8,9。
代码
public class demo8 {
public static void main(String[] args) {
int[] array = new int[]{1, -1, 5, -3, 4, 2, 7, 3};
//1,6,-8,6,4,2,7,3
//-8,1,6,6,4,2,7,3
//-8,1,6,6,4,2,7,3
//-8,1,4,6,6,2,7,3
//-8,1,2,4,6,6,7,3
//-8,1,2,4,6,6,7,3
//-8,1,2,3,4,6,6,7
System.out.println(Arrays.toString(insertionSort(array)));
}
public static int[] insertionSort(int[] array) {
for (int i = 1; i < array.length; i++) {
int temp = array[i];
// 从已经排序的序列最右边的开始比较,找到比其小的数
int j = i;
while (j > 0 && temp < array[j - 1]) {
array[j] = array[j - 1];
j--;
}
// 存在比其小的数,插入
if (j != i) {
array[j] = temp;
}
}
return array;
}
}
希尔排序(sell排序)
/**
* @author yaozh
* @date 2023/2/20 19:25
* 希尔排序
*/
public class ShellSort {
public static void main(String[] args) {
int[] array = new int[]{10, 8, 5, 3, 15, 4, 9, 5, 6};
System.out.println(Arrays.toString(shellSort(array)));
}
public static int[] shellSort(int[] array) {
int l = array.length;
int temp;
for (int grep = l / 2; grep >= 1; grep /= 2) {
for (int i = grep; i < l; i++) {
temp = array[i];
int j = i - grep;
while (j >= 0 && array[j] > temp) {
array[j + grep] = array[j];
j -= grep;
}
array[j + grep] = temp;
}
}
return array;
}
}
快速排序
原理:
首先定义两个指针,l和r,开始时都指向最左边和最右边,然后先从最右边的第一个数拿来与数组第一个数(key)比较,如果右边的数比key大,则右边指针向左移动一格,也就是 r-- ,一直到右边指针指向的数比key小为止,然后再比较 l 指针与key的大小,如果 l 指针指向的数比key小,则 l 指针向前移动一个,如果比他大,然后比较两个指针 r 是否与l相等,如果相等,交换key与他们指向的数组的值,如果不相等,则交换两个指针的值,然后继续移动指针,如果两个指针的初始值left>=right则退出循环,直到两个指针相遇,才完成一次最外层循环,然后在使用递归调用。
代码:
public class Demo5 {
public static void main(String[] args) {
int[] arr=new int[]{0,6,10,-5,1,3,-2,5,-5,10,6};
//0,-5,3,-2,5,1,10,6 第一次排序
//0,-5,-2,3,5,1,10,6 第二次排序
//-2,-5,0,3,5,1,10,6 三
//-5,-2,0
int[] array=quickSort(arr, 0, arr.length-1);
System.out.println(Arrays.toString(array));
}
public static int[] quickSort(int[] arr, int left, int right) {
//左指针
int l = left;
//右指针
int r = right;
//只要左右两个指针不相等就进行循环
while (l < r) {
while (l<r && arr[left]<=arr[r]){
r--;
}
while (l<r && arr[left]>=arr[l]){
l++;
}
if (l<r){
int temp=arr[l];
arr[l]=arr[r];
arr[r]=temp;
}
if (l==r){
int temp=arr[left];
arr[left]=arr[r];
arr[r]=temp;
}
}
//退出循环条件,被切分开的每一个小数组变成一个数时,排序完成,退出
if (left>=right){
return arr;
}
quickSort(arr,left,r-1);
quickSort(arr,l+1,right);
return arr;
}
}