八大排序-志宇

冒泡排序

思想
比较两个相邻元素,如果顺序错误则交换过来
总共比较数组长度减一次,每次比较 将 那次比较的最大值放到符合的位置
优化: 当有一次比较,数组中没有数字交换,则证明数组已经是有序的了
图解
在这里插入图片描述
代码

import java.util.Arrays;
//冒泡排序
public class BubbleSort {
    public static void main(String[] args) {
    	//长度是5   0   1  2   3   4 
		int arr[] ={3, 9, -1, 10, -2};
		boolean flag = false;
		for(int i=0;i<arr.length-1;i++){
			for(int j=0;j<arr.length-i-1;j++){
				if(arr[j] > arr[j+1]){
					flag = true;
					int temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
				}
			}
			System.out.println(Arrays.toString(arr));
			//在一趟排序没有发生交换则证明已经是有序的了
			if(flag){
				flag = false;
			}else{
				break;
			}
		}
	}
}

选择排序

思想
总共比较数组长度减一次
在每次比较中记录最大的数字的位置
将每次比较出来的最大数字所在位置和符合的位置进行交换
图解
在这里插入图片描述
代码

import java.util.Arrays;
//选择排序
public class SelectSort {
   public static void main(String[] args) {
	   int[] arr={101, 34, 119, 1};
	   
	   for(int i=0;i<arr.length-1;i++){
		   int min=i;
		   for(int j=i;j<arr.length;j++){
			   if(arr[min]> arr[j]){
				   min=j;
			   }
		   }
		   //最小值不在最小位置才交换
		   if(min!=i){
			   int temp=arr[i];
			   arr[i]=arr[min];
			   arr[min]=temp;
		   }
		   System.out.println(Arrays.toString(arr));
	   }
   }
}

插入排序

思想
好比整理扑克牌的顺序,
将要插入的牌拿出来和前一张牌比较,如果前一张牌比这张牌大 前一张牌后移, 要插入的牌再和前第二张牌比较,如果前第二张牌比这张牌大 前第二张牌后移
以此类推,直到找到符合的位置将这张牌插入
缺点
数组 arr = {2,3,4,5,6,1} 这时需要插入的数 1(最小), 这样的过程是:
{2,3,4,5,6,6}
{2,3,4,5,5,6}
{2,3,4,4,5,6}
{2,3,3,4,5,6}
{2,2,3,4,5,6}
{1,2,3,4,5,6}
结论: 当需要插入的数是较小的数时,后移的次数明显增多,对效率有影响.
图解
在这里插入图片描述
代码

public class InsertSort {
    public static void main(String[] args) {
		int[] arr={101, 34, 119, 1};
    	for(int i=1;i<arr.length;i++){
    		//存储要插入牌的位置
    		int index=i;
    		//存储要插入牌的值
    		int tempValue=arr[i];
    		//每次是和要插入牌的值比较
    		while(index >0 && tempValue < arr[index-1]){
    			arr[index]=arr[index-1];
    			index--;
    		}
    		if(index !=i){
               arr[index]=tempValue;
    		}
    		System.out.println(Arrays.toString(arr));
    	}
	}
} 

希尔排序

思想
希尔排序是 快速排序 基于 分治思想 的改进
将数组分成 数组长度除二个组(gap) 每个组进行插入排序
----只要时大于等于gap的数字都要要和前面进行比较排序
再将数组分成 gap/2 个数组进行插入排序
当gap为1时进行最后一次插入排序,即可获得有序序列
图解
在这里插入图片描述
代码

public class ShellSort2 {
   public static void main(String[] args) {
	      int[]  arr={8,9,1,7,2,3,5,4,6,0};
	      for(int gap=arr.length/2;gap>0;gap=gap/2){
	    	  for(int j=gap;j<arr.length;j++){
	    		  int temp=arr[j];
	    		  int index=j;
	    		  while(index-gap>=0 && temp<arr[index-gap]){
	    			  arr[index]=arr[index-gap];
	    			  index=index-gap;
	    		  }
	    		  if(index != j){
	    			  arr[index]=temp;
	    		  }
	    	  }
	    	  System.out.println(Arrays.toString(arr));
	      }
     }
} 

堆排序

思想
1.将待排序序列构造成一个大顶堆
----1.1 找到完全树的最后一个叶子节点(有子节点的节点)位置为数组长度/2-1
----1.2 从数组长度/2-1向前依次进行排序
2.此时,整个序列的最大值就是堆顶的根节点。
3.将其与末尾元素进行交换,此时末尾就为最大值。
4.然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。
5.如此反复执行,便能得到一个有序序列了。
大顶堆是升序排列,小顶堆是降序排列
图解
满二叉树:
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树
如下图: 2^3 -1=7 个节点
在这里插入图片描述
完全二叉树:
若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树
在这里插入图片描述

大顶堆

大顶堆:是完全二叉树,每个节点的值大于或等于它的左子节点和右子节点的值,没有要求结点的左子节点的值和右子节点的值的大小关系。
在这里插入图片描述
我们对堆中的结点按层进行编号,映射到数组中就是下面这个样子:

在这里插入图片描述
大顶堆特点:
arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2] // i 对应第几个节点,i从0开始编号
小顶堆
小顶堆:是完全二叉树,每个节点的值小于或等于它的左子节点和右子节点的值,没有要求结点的左子节点的值和右子节点的值的大小关系。
在这里插入图片描述
代码

public class HeapSort2 {
   public static void main(String[] args) {
	   int[] arr={4,6,8,5,9};
	   //1.将数组调整成大顶堆
	   //最后一个非叶子节点为  arr[arr.length/2-1]
	   for(int i=arr.length/2-1;i>=0;i--){
		   //将第i个非叶子节点,和子节点比较然后交换位置
		   maxHeapSort(arr,i,arr.length);
	   }
	  System.out.println(Arrays.toString(arr));
	
	  //每次将大顶堆的根节点和排序的最后一位交换
	  for(int i=0;i<arr.length;i++){
		  maxHeapSort(arr,0,arr.length-i);
		  int temp=arr[0];
		  arr[0]=arr[arr.length-i-1];
		  arr[arr.length-i-1]=temp;
		  System.out.println(Arrays.toString(arr));
	  }
   }
   /**
    * 
    * @param arr    要排序的数组
    * @param i      每次要排序的节点
    * @param length  因堆排序要每次得出最大值和排序的最后位替换,这里不用arr.length,因为长度会变化
    */
	private static void maxHeapSort(int[] arr, int i, int length) {
		//保存此节点的值
		int temp=arr[i];
		//arr[2*i+1]为arr[i]的左节点
		for(int k=2*i+1;k<length;k=2*k+1){
			//判断右子节点是否存在,指针指向左右子节点中的最大值
			if(k+1<length && arr[k+1]>arr[k]){
				k++;
			}
			//判断此节点的值是否 小于 子节点中的最大值
			if(temp < arr[k]){
				//此节点等于子节点的值
                arr[i]=arr[k];
                //将此节点坐标 变成 子节的坐标,用于和下次和子节点的子节点比较
                i=k;
			}else{
				break;
			}
			//当for 循环结束后,我们已经将以i 为父结点的树的最大值,放在了 最顶
			arr[k]=temp;
		}
	}
}

基数排序

思想
----计数排序:每个桶只存储单一键值;
----桶排序:每个桶存储一定范围的数值;
----基数排序:根据键值的每位数字来分配桶;
1、创建桶
----1.1如果排序是数字则创建10个桶,每个桶最大容量为序列长度
----1.2如果排序的是字母创建26个桶,每个桶最大容量为序列长度
----1.3创建一个数组用来标记每个桶中有多少个元素
2、将序列按要求放到桶中
----2.2 遍历序列中每个元素,获得指定位上的值
----2.3 根据获得指定位上的值将元素放到指定桶中,标记桶中元素个数的值增加
3、从桶中取出
----3.3按顺序遍历桶中的值,同时将值赋值给原数组
4、循环2和3最后得出有序序列
注意: 基数排序是经典的空间换时间的方式,占用内存很大, 当对海量数据排序时,容易造成 OutOfMemoryError
图解
在这里插入图片描述
代码


public class RadixSort2 {
   public static void main(String[] args) {
	   int[]arr = {73, 22, 93, 43, 55, 14, 28, 65, 39, 81, 33, 100};
	   sort(arr,3);
	   System.out.println(Arrays.toString(arr));
   }
    /**
     * @param arr 原数组 
     * @param i   原数组 最大数有几位数
     */
	private static void sort(int[] arr, int length) {
		//创建10个一维数组,每个数组中最大有arr.length个数
		int[][] tempArr=new int[10][arr.length];
		//用来标记每个一维数组中有几个数
		int[] indexArr=new int[10];
		//循环遍历某一位
		for(int i=0,n=1;i<length;i++,n=n*10){
			//遍历数组中每个元素值放到指定桶中
			for(int j=0;j<arr.length;j++){
				//得到数组中每个元素对应的桶
				/**
				 * 个位 /1  %10
				 * 十位  /10 %10
				 * 百位 /100 %10
				 */
				int val=arr[j]/n%10;
				//将元素放到指定桶,同时标记这个桶中的元素个数增加
				tempArr[val][indexArr[val]++]=arr[j];
			}
			int index=0;
			//将桶中数据放到原数组中
			for(int k=0;k<10;k++){
				for(int l=0;l<indexArr[k];l++){
					arr[index]=tempArr[k][l];
					index++;
				}
			}
			indexArr=new int[10];
		}
	}
}

归并排序

思想
采用分治思想,将数组拆分成每一个元素,然后合并时进行排序
图解
拆分
在这里插入图片描述
合并
绿色数组 和 红色数组 合并为一个 蓝色数组(temp数组)
蓝色和红色数组各有一个指针,通过比较指针后移按大小顺序取出放入temp数组中
在这里插入图片描述
代码

public class MergeSort {
    public static void main(String[] args) {
		int[] arr={9,8,7,6,5,4,3,2,1};	
		//创建缓存数组
    	int[] temp=new int[arr.length];
    	//调用归并排序
    	merge(arr,0,arr.length-1,temp);
    	System.out.println(Arrays.toString(arr));
	}
    /**
     * 进行拆分,然后调用合并
     * @param arr 原数组
     * @param i   拆分左边界
     * @param j   拆分右边界
     * @param temp  缓冲数组
     */
	private static void merge(int[] arr, int l, int r, int[] temp) {
		if(l<r){
			//取出中间值
			int mid=(l+r)/2;
			//拆分左面
			merge(arr,l,mid,temp);
			//拆分右面
			merge(arr,mid+1,r,temp);
			//合并
			mergeSort(arr,l,mid,r,temp);
	    	System.out.println(Arrays.toString(arr));
		}
	}
	/**
	 * 合并
	 * @param arr  要合并的数组
	 * @param l    要合并的左面开始位置
	 * @param mid  要合并的中间位置
	 * @param r    要合并的结束位置
	 * @param temp 缓冲数组
	 */
	private static void mergeSort(int[] arr, int l, int mid, int r, int[] temp) {
		int left=l; //要合并的左面数组的起始位置
		int right=mid+1;  //要合并的右面数组的起始位置
		int index=l;  //temp中存储数据的索引位置
		//一、将两个数组按大小顺序复制到temp数组中
		    //有两个数组要合并      一个数组的位置为 [l,mid] 另一个数组的位置为[mid+1,r]           
		while(left<=mid && right<=r){
			if(arr[left]<=arr[right])
			{
				temp[index]=arr[left];
				//缓存数组索引加1
				index++;
				//本数组索引加1
				left++;
			}else
			{
				temp[index]=arr[right];
				//缓存数组索引加1
				index++;
				//本数组索引加1
				right++;
			}
		}
		//将剩余的数组放到缓冲数组中
		while(left<=mid)
		{
			temp[index]=arr[left];
			index++;
			left++;
		}
		while(right<=r)
		{
			temp[index]=arr[right];
			index++;
			right++;
		}
		//二、将temp数组中的值替换给arr原数组中
		for(int i=l;i<=r;i++){
			arr[i]=temp[i];
		}
	}
}

快速排序

思想
采用分治思想
1.首先选取一个基准数
2.将小于基准数的数放倒基准数的左面
3.将大于基准数的数放到基准数的右面
4.一次递归拆分,直到数组有序
图解
1.首先选取一个基准数,这里选择基准数为19
设置最左面的位置为L
设置最右面的位置为R
在这里插入图片描述
2.将R处索引中的8和基准数进行比较,由于比基准数小则将8放到L索引处位置,
同时L索引后移一位
在这里插入图片描述
3.将L处索引数值取出和基准数比较,由于比基准数大,将97放到R处索引位置,同时R索引前移一位
在这里插入图片描述
4.将R处索引上的值和基准数比较,由于1比基准数小,将1放到L索引位置,同时L的索引后移1位
在这里插入图片描述
5.将L索引处的数和基准数比较,由于9比基准数小,L直接后移一位
将L索引处的数和基准数比较,由于17比基准数小,L直接后移一位
在这里插入图片描述
6.在L和R重合了,这时将基准数插入到重合的位置,得到第一次排序
在这里插入图片描述
代码

public class QuickSort {
	public static void main(String[] args) {
		int[] arr={-9,78,0,23,-567,70};
		quickSort(arr,0,arr.length-1);
		System.out.println(Arrays.toString(arr));
	}

	private static void quickSort(int[] arr, int left, int right) {
		//要将所有的操作放到这个判断中,如果在这个判断外递归会出现死循环
		if(left<right){
			//选取一个基准数
			int pivot=arr[left];
			int l=left;
			int r=right;
			
	        while (l < r)
	        {
	        	//从右往左找到一个小于基准数的数,没有找到的话R左移一位
				while(l<r && arr[r]>pivot){
					r--;
				}
				//将这个数插入到 L索引处,同时L索引坐标右移一位
				if(l<r){
					arr[l]=arr[r];
					l++;
				}
				//从左往右找到一个大于基准数的数,没有找到的话L右移一位
				while(l<r && arr[l]<pivot){
					l++;
				}
				//将这个数插入到 R索引处,同时R索引坐标左移一位
				if(l<r){
					arr[r]=arr[l];
					r--;
				}
	        }
	        //当L=R时将基准数插入到这个位置
			arr[l]=pivot;
			System.out.println(Arrays.toString(arr));
			quickSort(arr,left,l-1);
			quickSort(arr,l+1,right);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值