一.冒泡排序
1 思想
冒泡排序是使用第一个值和后续列表中的所有值进行比较,如果大于后续列表中的值那就进行位置的交换。
第一个值排好之后,使用第二个值与后续的值进行比较,如果大于后续列表中的值那就进行位置的交换。
第二个值排好之后,使用第三个值与后续的值进行比较,依次循环确定好每一个位置上的值。
当然 x个数只需要排 x - 1次
时间复杂度O(n²)·
2 代码流程
public static int[] popSortStep(int[] arr){
// 第一次排序
// 使用第一个位置上的值和后续的值进行比较
for(int i = 0 ,j = 1; j < arr.length; j++){
if(arr[i] > arr[j]){
int temp = arr[i];
arr[i] = arr[j]
arr[j] = temp
}
}
// 第二次排序
// 使用第二个位置上的值与后续值进行比较
for(int i = 1,j = 2; j < arr.length ; j++){
if(arr[i] > arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// 后续的排序依旧按照这个顺序来 i=2,j=i+1
return arr;
}
3.完整代码
public static int[] popSort(int[] arr){
// 排序的次数是数组元素个数 - 1
for(int i = 0 ; i < arr.length - 1 ; i++){
for(int j = i+1 ; j < arr.length ; j++){
if(arr[i] > arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
二.选择排序
1.思想
我们使用两个变量比如min和minIndex用来记录当前数组中的最小值和最小值的数组下标位置
先默认数组中的第一个值是最小的。然后使用min依次与后续的值比较,如果发现min大于后续列表中的值,
那就改变min和minIndex的值为较小一个的值。(这里就是与冒泡不同的地方,冒泡排序是发现小于当前值的话会直接交换,
而选择排序是选择记录的方式),当遍历完成后才判断minIndex是否改变了,如果改变了就进行交换。
第一次遍历完就确定将我们最小的值放到了列表的第一个位置。
然后开始对第二个值进行以上的操作。
时间复杂度O(n²)
2.代码流程
public static int[] selectSortStep(int[] arr){
// 第一次排序
// 先定下第一个位置上的值
// 先默认数组的第一个位置上的值是最小的
int min = arr[0];
int minIndex = 0;
// 使用这个最小值与后续值进行比较
for(int j = 1 ; j < arr.length - 1 ; j++){
// 如果当前的认定的最小值大于后面的值,就进行改变min,minIndex的值
if(min > arr[j]){
min = arr[j];
minIndex = i;
}
}
// 遍历完成后,可以判断数组第一个位置的值是否是最小的,不是就进行交换
if(minIndex != 0){
arr[minIndex] = arr[0];
arr[0] = min;
}
// 第二次排序
// 确定第二个位置上的值
// 先默认数组的第二个位置上的值是最小的
min = arr[1];
minIndex = 1;
for(int j = 2 ; j < arr.length - 1 ; j++){
if(min > arr[j]){
min = arr[j];
minIndex = i;
}
}
if(minIndex != 1){
arr[minIndex] = arr[1];
arr[0] = min;
}
return arr;
}
3.完整代码
public static int[] selectSort(int[] arr){
// 这里排序的次数也是数组元素个数-1
for(int i = 0 ; i < arr.length - 1 ; i++){
int min = arr[i];
int minIndex = i;
for(int j = i + 1; j < arr.length ; j++){
if(min > arr[j]){
min = arr[j];
minIndex = i;
}
}
if(minIndex != i){
arr[minIndex] = arr[i];
arr[i] = min;
}
}
return arr;
}
三.插入排序
1.思想
我们将待排序的数组看成两部分,一部分是有序的,一部分是无序的,将无序的数组中的元素插入到有序数组中去,直到无序的数组中没有任何一个元素。
把 n 个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有 n-1 个元素
比如:我们将数组的第一个元素看成是一个有序的,后面的元素都是无序的。
2.代码流程
public void static sortOne(int[] arr){
// 第一次排序
// 记录数组中的当前值
int insertVal = arr[1];
// 记录当前值要插入位置的前一个元素
int insertIndex = 1 - 1;
// 通过循环来找到我们要插入值的位置
// 当insertIndex小于0时,说明已经到达了第一个位置
// 当insertVal > arr[insertIndex]时。说明已经找到了当前值的一个合适位置
while(insertIndex >= 0 && insertVal < arr[insertIndex]){
// 将前一个值后移
arr[insertIndex+1] = arr[insertIndex];
// 将记录要插入位置的指针前移
insertIndex--;
}
// 当循环结束后,要么是达到了第一个位置,要么是已经找到了合适的位置
arr[insertIndex+1] = indexVal;
// 第二次排序
insertVal = arr[2];
insertIndex = 2 - 1;
while(insertIndex >= 0 && insertVal < arr[insertIndex]){
arr[insertIndex+1] = arr[insertIndex];
insertIndex--;
}
arr[insertIndex+1] = indexVal;
}
3.完整代码
public static void sortInsert(int[] arr){
// 进入循环,从第二个值开始
for(int i = 1 ; i< arr.length ; i++){
// 记录当前值
int insertVal = arr[i];
// 记录要插入位置的前一个值
int insertIndex = i - 1;
while(insertIndex >= 0 && insertVal < arr[insertIndex]){
arr[insertIndex+1] = arr[insertIndex];
insertIndex--;
}
// 跳出while循环后,说明已经找到合适的插入位置
// 优化方案,如果当前值的最佳位置就是当前位置的话,那么就不用进行交换,反之,则要交换
if(insertIndex + 1 != i){
arr[insertIndex + 1] = insertVal;
}
}
}
四.希尔排序
1.思想
我们将要排序的数组进行一个分组的操作,比如一共10个元素,10/2=5,把数组分成5组,每组两个元素,分别进行排序。当排序完一次后,再进行分组 5/2=2,分成两组的形式,再进行排序。最后2/2=1,最后再进行整个组内的排序。
2.代码流程
public static void sortOne(int[] arr){
// 我们假设数组的长度是10
// 第一次排序
int gap = 5 // 10/2
// 分为5个组,初始增量是5
for(int i = gap ; i < arr.length ; i++){
//j的循环是一个插入排序,和前面的有序数组进行比较。
// 先和后面的值进行比较,再和前面的值进行比较
for(int j = i - gap ; j >= 0 ; j -=gap){
if(arr[j] > arr[j + gap]){
int temp = arr[j];
arr[j] = arr[j + gap];
arr[j+gap] = temp;
}
}
}
// 第二次排序
int gap = 5/2 // 10/2
// 分为2个组,初始增量是2
for(int i = gap ; i < arr.length ; i++){
//让一个元素和其前面的元素进行比较
for(int j = i - gap ; j >= 0 ; j -=gap){
if(arr[j] > arr[j + gap]){
int temp = arr[j];
arr[j] = arr[j + gap];
arr[j+gap] = temp;
}
}
}
3.完整代码
public void static sortShell(int[] arr){
// 增量的循环
for(int gap = arr,length / 2 ; gap > 0 ; gap /= 2){
for(int i = gap ; i < arr,length ; i++){
for(int j = i- gap; j >= 0 ; j-= gap){
if(arr[j] > arr[j+gap] ){
int temp = arr[j];
arr[j] = arr[j + gap];
arr[j+gap] = temp;
}
}
}
}
}
五.快速排序
1.思想
是冒泡排序法的改进方案,以中间的节点为基准,小于中间节点的放在左边,大于中间节点的放在右边。
先找到左边比中间节点大的值,再找到右边比中间节点小的值,然后进行交换位置。
当我们的左指针到了中间,右指针也到了中间,那就使用递归,改变中间值。
使用递归的方式依次进行排序。
2.代码流程
public static void sortOne(int[] arr,int left , int right){
// 记录当前数组中最左边的值
int l = left;
// 记录当前数组中最右边的值
int r = right;
// 记录当前数组中间的节点位置
int mid = (r+l)/2;
// 一个临时的值,用来交换使用
int tenmp = 0;
while(l > r){
// 这个循环是为了找到比中间节点大的值
while(arr[l] < arr[mid]){
l++;
}
// 这个循环是为了找到比中间节点小的值
while(arr[r] > arr[mid]){
r--;
}
// 判断是不是都是到了中间了,大于就要退出了
if(l >=r){
break;
}
// 进行左右值的交换
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
// 如果这时候左边的指针达到了中间,那么就将右边的指针移动
if(l == mid){
r--;
}
// 如果这时候右边的指针达到了中间,那么就将左边的指针移动
if(r == mid){
l++;
}
}
}
3.完整代码
public static void quickSort(int[] arr,int left , int right){
// 当前数组中最右边的指针
int l = left;
// 当前数组中最左边的指针
int r = right;
// 设置当前数组中的中间节点
int mid = (l+r)/2;
while(l < r){
// 开始找左边比中间值大的数
while(arr[l] < arr[mid]){
l++;
}
// 开始找右边比中间值小的数
while(arr[r] > arr[mid]){
r--;
}
// 判断r和l是否都已经到中间了,到了就结束循环
if(l >= r){
break;
}
// 进行交换位置
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
// 如果左边的指针到了中间,那么就移动右边的指针
if(l == mid){
r--;
}
// 如果右边的指针到了中间,那么就移动左边的指针
if(r == mid){
l++;
}
}
//开始向左向右递归排序
// 如果两个值都在中间的话,就各自移动一位
if(l == r){
l--;
r++;
}
// 向左递归
if(l < right){
quickSort(arr,l,right);
}
// 向右递归
if(left < r){
quickSort(arr,left,r);
}
}
六.归并排序
1.思想
归并排序就是使用的分治算法,先将数组化整为零,将数组分为一个个的数,
然后再合并,将数组中的数从小到大的放到一个临时数组中。最后再放回原本的数组中。
2.合并的代码流程
public static void merge(int[] arr,int left , int mid , int right,int[] temp){
// 左边的初始索引
int l = left;
// 右边的初始索引
int r = mid + 1;
// 临时数组中的索引
int tempIndex = 0;
// 先将一个数组中的数放到临时数组中
while(l <= mid && r <= right){
// 如果左边的值小,那么就将左边的值放入到临时数组中
if(arr[l] < arr[r]){
temp[tempIndex] = arr[l];
l++;
tempIndex++;
}
// 如果右边的值小,那么就将右边的值放入到临时数组中
if(arr[r] < arr[l]){
temp[tempIndex] = arr[r];
r++;
tempIndex++;
}
}
// 退出循环后,说明有一个数组中的值已经全部添加到临时数组中
// 接下来将另外一个数组中的值添加到临时数组中
while(l <= mid){
temp[tempIndex] = arr[l];
l++;
tempIndex++;
}
while(r <= right){
temp[tempIndex] = arr[r];
r++;
tempIndex++;
}
// 接下来就将临时数组中的值放入到原始数组中
// 设置原始数组中的下标
int leftIndex = left;
// 将临时数组中的下标初始化
tempIndex = 0;
// 将临时数组中的值放到原始数组中
while(leftIndex <= right){
arr[leftIndex] = temp[tempIndex];
leftIndex++;
tempIndex++;
}
}
3.完整代码
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 l = left;
// 右边的初始索引
int r = mid + 1;
// 临时数组中的索引
int tempIndex = 0;
// 先将一个数组中的数放到临时数组中
while(l <= mid && r <= right){
// 如果左边的值小,那么就将左边的值放入到临时数组中
if(arr[l] < arr[r]){
temp[tempIndex] = arr[l];
l++;
tempIndex++;
}
// 如果右边的值小,那么就将右边的值放入到临时数组中
if(arr[r] < arr[l]){
temp[tempIndex] = arr[r];
r++;
tempIndex++;
}
}
// 退出循环后,说明有一个数组中的值已经全部添加到临时数组中
// 接下来将另外一个数组中的值添加到临时数组中
while(l <= mid){
temp[tempIndex] = arr[l];
l++;
tempIndex++;
}
while(r <= right){
temp[tempIndex] = arr[r];
r++;
tempIndex++;
}
// 接下来就将临时数组中的值放入到原始数组中
// 设置原始数组中的下标
int leftIndex = left;
// 将临时数组中的下标初始化
tempIndex = 0;
// 将临时数组中的值放到原始数组中
while(leftIndex <= right){
arr[leftIndex] = temp[tempIndex];
leftIndex++;
tempIndex++;
}
}