九大排序
1.冒泡排序
1.1介绍
- 一种简单的排序算法。 它重复地走访过要排序的数列,-次比较两个元素,如果它们的顺序
错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数
列E经排序完成。这个算法的名字由来是因为元素会经由交换慢慢’浮到数列的顶端。
1 、比较相邻的元素。如果第一个比第二 个大,就交换它们两个;
2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对, 这样在最后的元素应该会是最大的数;
3、针对所有的元素重复以上的步骤,除了最后一个;
4、重复步骤1~3,直到排序完成
1.2代码
public class 冒泡排序 {
public static void main(String[] args) {
int [] arr={7,6,8,4,6,3};
int tem=0;
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){
tem=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tem;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
2.选择排序
2.1介绍
- 选择排序的思想其实和冒泡排序有点类似,选择排序可以看成冒泡排序的优化。
■ 首先,找到数组中最大(小)的那个元素;
■其次,将它和数组的第一个元素交换位置 (如果第一个元素就是最大 (小)元素那么它就和
自己交换) ;
■再次,在剩下的元素中找到最大(小)的元素,将它与数组的第二个元素交换位置。如此往
复,直到将整个数组排序。
■这种方法叫做选择排序, 因为它在不断地选择剩余元素之中的最大(小)者。
■视频讲解:https://www.bilibili.com/video/BV1hi4y1k7Ho/?p=31&vd_source=0dab08b89546a14d977a0ff90dbc9e7d
2.2代码
public class 选择排序 {
public static void main(String[] args) {
int [] arr={7,6,8,4,6,3};
for(int i=0;i<arr.length;i++){
int minIndex=i;/*最小数的下标,每个循环开始总是假设第一个数最小*/
for(int j=i;j<arr.length;j++){
if(arr[minIndex]>arr[j]){ /*找到最小的数*/
minIndex=j; /*将最小数的索引保存*/
}
}
System.out.println("最小数为:"+arr[minIndex]);
/*交换最小数和i当前所指的元素*/
int tem=arr[i];
arr[i]=arr[minIndex];
arr[minIndex]=tem;
System.out.println(Arrays.toString(arr));
System.out.println("----------------------------");
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
3.插入排序
3.1介绍
- 对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
- 为 了给要插入的元素腾出空间,我们需要将插入位置之后的已排序元素在都向右移动一位。
插入排序所需的时间取决于输入中元素的初始顺序。例如,对一个很大且其中的元素已经有序(或接近有序)的数组进行排序将会比对随机顺序的数组或是逆序数组进行排序要快得多。
总的来说,插入排序对于部分有序的数组十分高效,也很适合小规模数组。 - 视频讲解:https://www.bilibili.com/video/BV1hi4y1k7Ho/?p=32&vd_source=0dab08b89546a14d977a0ff90dbc9e7d
3.2代码
public class 插入排序 {
public static void main(String[] args) {
int [] arr={6,1,2,7,9,3,4,5,10,8};
System.out.println("============================================");
int[] dest = sortArray(arr);
System.out.println(Arrays.toString(dest));
}
public static int[] sortArray(int[] nums) {
if (nums.length == 0)
return nums;
int currentValue;/*当前待排序数据,该元素之前的元素均已被排序过*/
for (int i = 0; i < nums.length - 1; i++) {
int preIndex = i;/*已被排序数据的索引*/
currentValue = nums[preIndex + 1];
System.out.println("待排序元素索引:"+(i + 1)+",值为:" +currentValue+
",已被排序数据的索引:"+preIndex);
/*在已被排序过数据中倒序寻找合适的位置,如果当前待排序数据比比较的元素要小,
将比较的元素元素后移一位*/
while (preIndex >= 0 && currentValue < nums[preIndex]) {
//将当前元素后移一位
nums[preIndex + 1] = nums[preIndex];
preIndex--;
System.out.println(Arrays.toString(nums));
}
/*while循环结束时,说明已经找到了当前待排序数据的合适位置,插入*/
nums[preIndex + 1] = currentValue;
System.out.println("本轮被插入排序后的数组");
System.out.println(Arrays.toString(nums));
System.out.println("--------------------");
}
return nums;
}
}
4.希尔排序(插入排序的优化)
4.1介绍
- 一种基于插入排序的快速的排序算法。简单插入排序对于大规模乱序数组很慢,因为元素只
能一点一点地从数组的一端移动到另一端。 - 希尔排序为了加快速度简单地改进了插入排序,也称为缩小增量排序,同时该算法是冲破
O(n^2)的第一批算法之一。 - 希尔排序是把记录按下表的一定增量分组,对每组使用直接插入排序算法排序;然后缩小增
量继续分组排序,随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文
件恰被分成一组, 再次排序,完成整个数组的排序。这个不断缩小的增量,就构成了一个增
量序列。 - 视频讲解:https://www.bilibili.com/video/BV1hi4y1k7Ho/?p=34&vd_source=0dab08b89546a14d977a0ff90dbc9e7d
4.2代码
public class 希尔排序_插入排序的优化 {
public static void main(String[] args) {
int [] arr={6,1,2,7,9,3,4,5,10,8};
System.out.println("============================================");
int[] dest = sortArray(arr);
System.out.println(Arrays.toString(dest));
}
public static int[] sortArray(int[] nums) {
int len = nums.length;
/*按增量分组后,每个分组中,temp代表当前待排序数据,该元素之前的组内元素均已被排序过*/
/*gap指用来分组的增量,会依次递减*/
int currentValue, gap = len / 2;
while (gap > 0) {
for (int i = gap; i < len; i++) { //for循环里面就是一个插入排序
currentValue = nums[i];
/*组内已被排序数据的索引*/
int preIndex = i - gap;
/*在组内已被排序过数据中倒序寻找合适的位置,如果当前待排序数据比比较的元素要小,
则将比较的元素在组内后移一位*/
while (preIndex >= 0 && nums[preIndex] > currentValue) {
nums[preIndex + gap] = nums[preIndex];
preIndex -= gap;
}
/*while循环结束时,说明已经找到了当前待排序数据的合适位置,插入*/
nums[preIndex + gap] = currentValue;
}
System.out.println("本轮增量【"+gap+"】排序后的数组");
System.out.println(Arrays.toString(nums));
System.out.println("--------------------");
gap /= 2;
}
return nums;
}
}
5.归并排序(分治法)
5.1介绍
- 对于给定的一组数据,利用递归与分治技术将数据序列划分成为越来越小的半子表,在对半
子表排序后,再用递归方法将排好序的半子表合并成为越来越大的有序序列。 - 为了提升性能,有时我们在半子表的个数小于某个数的情况下,对半子表的排序采用其他排序
算法,比如插入排序。 - 若将两个有序表合并成一个有序表, 称为2-路归并,与之对应的还有多路归并。
- 视频讲解:https://www.bilibili.com/video/BV1hi4y1k7Ho/?p=35&vd_source=0dab08b89546a14d977a0ff90dbc9e7d
5.2代码
public class 归并排序 {
public static void main(String[] args) {
int [] arr={7,6,8,4,6,3};
int [] arr2=sortArray(arr);
System.out.println(Arrays.toString(arr2));
}
public static int[] meger(int[] left,int[] right){
int [] result=new int[left.length+right.length];
for (int i = 0,index=0,j=0 ;index <result.length ; index++) {
if(i>=left.length){ /*左边数组已经取完,完全取右边数组的值即可*/
result[index]=right[j++];
}else if(j>=right.length){ /*右边数组已经取完,完全取左边数组的值即可*/
result[index]=left[i++];
}else if(left[i]>right[j]){ /*左边数组的元素值大于右边数组,取右边数组的值*/
result[index]=right[j++];
}else { /*右边数组的元素值大于左边数组,取左边数组的值*/
result[index]=left[i++];
}
}
System.out.println("左子数组");
System.out.println(Arrays.toString(left));
System.out.println("右子数组");
System.out.println(Arrays.toString(right));
System.out.println("合并后数组");
System.out.println(Arrays.toString(result));
System.out.println("-----------------------");
return result;
}
public static int [] sortArray(int []nums){
if(nums.length<2){ /*切分数组,然后递归排序,并用merge合并*/
return nums;
}
int mid= nums.length/2;
int [] left=Arrays.copyOfRange(nums,0,mid);
int [] right=Arrays.copyOfRange(nums,mid,nums.length);
return meger(sortArray(left),sortArray(right));//归并排序——将两段排序好的数组结合成一个排序数组
}
}
6.快速排序(分治法)
介绍
- 快速排序(Quicksort)是对冒泡排序的一种改进,也是采用分治法的一个典型的应用。
- 首先任意选取一个数据(比如数组的第一个数)作为关键数据,我们称为基准数,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序,也称为分区(partition)操作。
- 通过一趟快速排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
6.1左右指针法
代码:
public class 快速排序_左右指针法 {
public static void main(String[] args) {
int[] arr = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8};
int[] arr2 = quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr2));
}
public static void swap(int[] array, int low, int hi) {
int tmp = array[low];
array[low] = array[hi];
array[hi] = tmp;
}
public static int Quick_Sort(int[] array, int low, int hi) {
int stoneValue = array[low];
// save stone index 最后记得把 stone 放到中间位置
int oldStoneIndex = low;
while (low < hi) {
// first hi
// hi 从右向左移,如果 值小于 stone hi ++ ;如果大于去和左边low互换,小值 最后全跑左边
while (low < hi && array[hi] >= stoneValue) {
hi--;
}
// low 从左向右移,如果 值小于 stone hi ++ ;如果大于去和左边low互换,小值 最后全跑左边
while (low < hi && array[low] <= stoneValue) {
low++;
}
// 互换 low,hi 值,小值跑左边,大值跑右边;
if (low < hi) {
int tmp = array[low];
array[low] = array[hi];
array[hi] = tmp;
System.out.println("left ,right swap low:" + low + " hi:" + hi
+ " array:" + Arrays.toString(array));
}
}
// 最后把 stone 移到相应位置
if (low == hi) {
swap(array, oldStoneIndex, hi);
System.out.println("stone Index :" + oldStoneIndex
+ " divideIndex:" + hi + " move stone swap :"
+ Arrays.toString(array));
}
return low;
}
public static int[] quickSort(int[] array, int low, int hi) {
if (low < hi) {
// array[low] get divideIndex divice two part;
int divideIndex = Quick_Sort(array, low, hi);
// 由 stone 分两部分,左边小值,右边大值
// 继续递归
quickSort(array, low, divideIndex - 1);
quickSort(array, divideIndex + 1, hi);
}
return array;
}
}
具体可以看这篇博客:文章链接
6.2前后指针法
代码:
public class 快速排序_前后指针法 {
public static void main(String[] args) {
int[] arr = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8};
int[] arr2 = quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr2));
}
private static int partition2(int[] array, int low, int high) {
int d = low + 1;
int tmp = array[low];
for (int i = low + 1; i <= high; i++) {
if (array[i] < tmp) {
swap(array, i, d);
d++;
}
}
System.out.println(Arrays.toString(array));
swap(array, d - 1, low);
return d - 1;
}
public static int[] quickSort(int[] array, int left, int right) {
if (left >= right) return array;
int pivot = partition2(array, left, right);
quickSort(array, left, pivot - 1);
quickSort(array, pivot + 1, right);
return array;
}
public static void swap(int[] array, int low, int hi) {
int tmp = array[low];
array[low] = array[hi];
array[hi] = tmp;
}
}
前后指针法原理:视频讲解
7.计数排序
7.1介绍
- 计数排序是一个排序时不比较元素大小的排序算法。
- 计数排序对一定范围内的整数排序时候的速度非常快,一般快于其他排序算法。但计数排序
局限性比较大,只限于对整数进行排序,而且待排序元素值分布较连续、跨度小的情况。 - 如果一个数组里所有元素都是整数,而且都在0-K以内。那对于数组里每个元素来说,如果能
知道数组里有多少项小于或等于该元素,就能准确地给出该元素在排序后的数组的位置。 - 视频讲解
7.2代码
public class 计数排序 {
public static void main(String[] args) {
int[] array = {95, 94, 91, 98, 99, 90, 99, 93, 91, 92};
int[] sortedArray = SoutArray(array);
System.out.println(Arrays.toString(sortedArray));
}
public static int[] SoutArray(int[] nums){
int bias,max=nums[0],min=nums[0];
/*寻找数组中最大值,最小值
* bias:偏移量,用以定位原始数组每个元素在计数数组中的下标位置*/
for(int i=1;i<nums.length;i++){
if(nums[i]>max){
max=nums[i];
}
if(nums[i]<min){
min=nums[i];
}
}
bias=min;
/*获得计数数组的容量*/
System.out.println(max-min);
int[] countArray=new int[max-min+1];
/*遍历整个原始数组,将原始数组中每个元素值转化为计数数组下标,
并将计数数组下标对应的元素值大小进行累加*/
for (int i = 0; i < nums.length; i++) {
countArray[nums[i]-bias]++;
}
System.out.println("计数数组为:");
System.out.println(Arrays.toString(countArray));
System.out.println("============================================");
int index=0;/*访问原始数组时的下标计数器*/
int i=0;/*访问计数数组时的下标计数器*/
/*访问计数数组,将计数数组中的元素转换后,重新写回原始数组*/
while(index<nums.length){
/*只要计数数组中当前下标元素的值不为0,就将计数数组中的元素转换后,重新写回原始数组*/
if(countArray[i]!=0){
nums[index]=i+bias;
countArray[i]--;
index++;
}else{
i++;
}
}
return nums;
}
}
8.桶排序
8.1介绍
- 桶排序是计数排序的升级版。
- 桶排序(Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序)。
- 视频讲解
8.2 代码
public class 桶排序 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(5);
list.add(2);
list.add(2);
list.add(6);
list.add(9);
list.add(0);
list.add(3);
list.add(4);
List<Integer> bucketSort = bucketSort(list, 2);
System.out.println(bucketSort);
}
public static List<Integer> bucketSort(List<Integer> array,int bucketSize) {
//合法性校验
if (array == null || array.size() < 2 || bucketSize < 1) {
return array;
}
//找出集合中元素的最大值和最小值
int max = array.get(0);
int min = array.get(0);
for (int i = 0; i < array.size(); i++) {
if (array.get(i) > max) {
max = array.get(i);
}
if (array.get(i) < min) {
min = array.get(i);
}
}
//计算桶的个数 集合中的最小值到最大值 判断桶的个数
int bucketCount = (max - min) / bucketSize + 1;
//按照顺序创建桶 创建一个list带下标
List<List<Integer>> bucketList = new ArrayList<>();
for (int i = 0; i < bucketCount; i++) {
bucketList.add(new ArrayList<Integer>());
}
//将待排序的集合依次添加到对应的桶中
//首先找到元素所对应的桶的顺序 再将元素添加到桶中
for (int j = 0; j < array.size(); j++) {
int bucketIndex = (array.get(j) - min) / bucketSize;
bucketList.get(bucketIndex).add(array.get(j));
}
//将桶内的元素进行排序
List<Integer> resultList = new ArrayList<>();
for (int j = 0; j < bucketList.size(); j++) {
List<Integer> everyBucket = bucketList.get(j);
if (everyBucket.size() >0) {
if (bucketCount == 1) {
bucketSize--;
}
//递归调用 进行排序
List<Integer> temp = bucketSort(everyBucket,bucketSize);
for (int i = 0; i < temp.size(); i++) {
//合并数据
resultList.add(temp.get(i));
}
}
}
return resultList;
}
}