package com.anji.allways.business.sales.service.impl;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* <pre>
* 排序算法
* </pre>
*
* @author shenke
* @version $Id: AddressController.java, v 0.1 2019年6月19日 上午9:51:39 shenke Exp $
*/
@Component
public class Sort {
/**
* 冒泡排序
* 逻辑:比较相邻元素,大者右移
* 外层循环代表元素个数,需要进行的排序次数;
* 内层循环:比较数组中相邻元素大小,从a[0]开始,a[a.length-1-i]结束,随着外层循环进行,内层循环次数逐次减少
* 注意:如a[5,4,3,2,1] i < a.length-1 即 (i < 4) 非 i < a.length (i < 5),因为循环从0开始,0-3还是循环4次,n个元素,外层循环n-1次
*
* @return
*/
public static int[] maopaoSort(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - 1 - i; j++) {
if (a[j] > a[j + 1]) {
swap(a, j, j + 1);
}
}
}
return a;
}
public static void swap(int[] a, int n, int m) {
int temp;
temp = a[n];
a[n] = a[m];
a[m] = temp;
}
public static void main(String[] args) {
int[] maopao = {3, 2, 1};
int[] insert = {6, 5, 4};
int[] insertTwo = {3, 2, 8, 1, 9, 5, 4, 7};
int[] insertThree = {3, 2, 8, 1};
//maopaoSort(maopao);
//insertSortOne(insert);
insertSotTwo(insertThree);
//insertSortThree(insertThree);
//insertSortFour(insertThree);
//System.out.println("冒泡排序后:" + Arrays.toString(maopao));
//System.out.println("插入排序后:" + Arrays.toString(insert));
System.out.println("插入排序2后:" + Arrays.toString(insertThree));
//System.out.println("插入排序3后:" + Arrays.toString(insertThree));
//System.out.println("插入排序4后:" + Arrays.toString(insertThree));
}
/**
* 插入排序(四种实现方式)
* <p>
* 中心思想:向前比较 代码实现方式 j = i j--
*
* <p>
* int[] a = {3, 2, 8, 1};
* 逻辑:交换的方式实现(当前元素向前交换)
* 1,j = 1,初次循环:假定第一个元素位置正确,新元素a[1]与第一个元素比较,a[j-1=0]>a[j=1],交换a[0] a[1]
* 2,后续循环:外层循环2,(外层循环1 处理后 a = {2, 3, 8, 1})
* 2.1)内层循环1(j = i = 2 假定a[2]为目标元素),a[2] = 8 大于a[1] = 3,因为取a[2] = 8时,其前面元素都是已经排好序的,后续无需再作比较
* 2.2)内层循环2(j = i = 1 假定a[1]为目标元素),a[1] = 3 大于a[0] = 2 (不需要)
* 3,外层循环3 (2处理后 a = {2, 3, 8, 1})
* 3.1)内层循环1(j = i = 3 假定a[3]为目标元素),交换a[3] a[2] a = {2, 3, 1, 8}
* 3.2)内层循环2(j = i = 2 假定a[2]为目标元素),交换a[2] a[1] a = {2, 1, 3, 8}
* 3.3)内层循环3(j = i = 1 假定a[1]为目标元素),交换a[1] a[0] a = {1, 2, 3, 8}
* <p>
* 交换方式与移动方式区别
* 不同
* 每次循环,比较并交换,新元素的下标不停的变动 vs 后移大数,循环结束,确定新元素的下标
*
* @return
*/
public static int[] insertSortOne(int[] a) {
for (int i = 1; i < a.length; i++) {
int j = i;
while (j > 0 && a[j] < a[j - 1]) {
swap(a, j, j - 1);
j--;
}
}
return a;
}
/**
* int[] a = {3, 2, 8, 1};
* 逻辑:交换的方式实现(当前元素向后交换)
* 1,外层循环1 i = 0,j < 0 内层不执行
* 2,外层循环2 i = 1
* 2.1)j = 0 a[0] a[1]比较,a = {2, 3, 8, 1}
* 3,外层循环3 i = 2
* 3.1)j = 1 a[1] a[2]比较 a = {2, 3, 8, 1}
* 3.2)j = 0 a[0] a[1]比较 a = {2, 3, 8, 1}
* 4,外层循环4 i = 3
* 4.1)j = 2 a[2] a[3]比较 a = {2, 3, 1, 8}
* 4.2)j = 1 a[1] a[2]比较 a = {2, 1, 3, 1}
* 4.3)j = 0 a[0] a[1]比较 a = {1, 2, 3, 1}
* <p>
* 比较方法3不同之处
* 相同
* 1,都有新元素的概念
* 2,都是默认第一个元素a[0]已排好
* 3,新元素来到前,前面的元素已排好序
* 4,都是向前比较 通过j--控制
* <p>
* 不同
* 1,控制新元素方式:j=i-1 vs j=i
* 2,每次循环,新元素的下标不停的变动 vs 循环结束,确定新元素的下标
* 3,交换元素位置 vs 后移元素位置
* <p>
* 特别注意:内层循环:如i = 2 for(int j = i - 1 j >= 0 j--)会执行两次,每次j是会递减的,不是i = 2,每次执行循环j = i -1 都等于1,所以int j = i-1仅仅是给j一个初始值
*
* @param a
* @return
*/
public static int[] insertSotTwo(int[] a) {
for (int i = 0; i < a.length; i++) {
for (int j = i - 1; j >= 0; j--) {
if (a[j] > a[j + 1]) {
swap(a, j, j + 1);
} else {
break;
}
}
}
return a;
}
/**
* [] a = {3, 2, 8, 1};
* 思想:
* 1,j = 1,,第一个新元素来了a[1],假定第一个元素(目标元素)的位置正确,即a[0],新拿到扑克a[1],与第一个元素a[0]比较
* 1.1)a[1] > a[0] 假设正确
* 1.2)a[1] < a[0](3 > 2>) 大数后移,把大数a[0]给a[1],j-- = 0,循环结束,新元素给到正确的位置a[0],处理后 a = {2, 3, 8, 1}
* 2,比较移动,不是比较交换(大数后移,循环结束后,找到目标元素正确位置,给值)
* 3,j = 2,第二个新元素来了a[2],a[1]处理后:int[] a = {2, 3, 8, 1};
* 3.1)理解为手里有扑克2,3,现在拿到扑克8放在哪个位置,而且手里的牌排序永远正确
* 3.2)目标元素 a[2] = 8,8与a[1]=3比较,8与a[0]=2比较,均大于;既然前面都是排好的,只比较目标元素前一个即可(循环结束,新元素8的下标正确a[2])。
* 3.3)j = 3,第三个个新元素来了a[3]=1,与a[2]比较,a[2]>a[3],后移a[2](把a[2]=8 给到a[3]位置),同时记录新元素正确下标(3-1=2)
* (且注意a[2]=8,还是之前的数据,并没有被新元素1取代),排序后 int[] a = {2, 3, 8, 8};
* j = 2,继续执行循环,《注意:每次比较都是拿新元素target a[3]=1,与前面元素作比较》,目标元素target值与a[j-1=1]比较,a[1]=3>1,3后移 a[2]=3,此时int[] a = {2, 3, 3, 8},j-- = 1
* j = 1,target=1,与a[1-1=0]=2比较,a[0]=2 > 1,后移2,a[j=1]=2,此时int[] a = {2, 2, 3, 8},j-- = 0
* j = 0,循环结束,target的正确下标j = 0,a[0]=1,此时int[] a = {1, 2, 3, 8}
* 4,拿到的新扑克(即数组中需要进行排序的数据),与手里已经排序的扑克(即目标数据前面的数据)比较
* 4.1)当前元素小于前一个元素,逐个比较
* 4.2)当前元素大于前一个元素,即大于前面所有元素,结束循环(方法4优化)
* <p>
* 再总结:
* 1,一直是拿新元素与前面所有元素比较,后移比它大的元素
* 2,不断定位到新元素的正确下标
* 3,循环结束,把新元素给到正确下标
*
* @param a
*/
public static void insertSortThree(int[] a) {
for (int i = 1; i < a.length; i++) {
int j = i;
int target = a[i];// 目标元素(新拿到扑克)
while (j > 0 && target < a[j - 1]) {//比较目标元素和前面每一个元素
a[j] = a[j - 1];// 后移大数
j--;// 目标元素正确位置
}
a[j] = target;// 目标元素给到正确位置
}
}
/**
* 优化 for 代替 while 添加break
* int[] a = {3, 2, 8, 1}
* 逻辑:
* 1,当前元素大于前一个元素,即大于前面所有元素,结束循环
*
* @param a
*/
public static void insertSortFour(int[] a) {
for (int i = 1; i < a.length; i++) {
int target = a[i];// 目标元素(新拿到扑克)
int j = i;
for (; j > 0; ) {//注意此处循环写法
//for (int j = i; j > 0; ) { 错误写法 j在变动
if (target < a[j - 1]) {//比较目标元素和前面每一个元素
a[j] = a[j - 1];// 后移大数
j--;// 目标元素正确位置
} else {
break;
}
a[j] = target;// 目标元素给到正确位置
}
}
}
}