经典排序算法java实现,整理了一些自己的通俗想法

1、排序算法说明

1.1 排序的定义

	对一序列对象根据某个关键字进行排列,使其有序。

1.2 相关定义

	稳定性:对于一个排序算法,在对一个序列进行排序时,有两个相同的元素a和b且a=b,如果排序之后a和b的相对前后位置没有发生变化,则称排序算法是稳定的,否则是不稳定的。

1.3 算法总结

2、算法实现

2.1 冒泡排序

冒泡排序 是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

  1. 原理
    · 比较相邻的元素,如果第一个比第二个大,就交换他们两个。
    · 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。
    · 针对所有的元素重复以上的步骤,除了最后一个,直到没有任何一对数字需要比较。
    (做一个小小的改进,设置一个标志位,如果数列已经有序(没有执行元素交换),则结束循环)。
  2. 代码实现
/**
	 * 优化冒泡排序
	 * <p>Title: bubbleSort</p>  
	 * <p>Description: </p>  
	 * @param array
	 * @return 
	 */
	public static int[] bubbleSort(int []array) {
		boolean flag=true;//设定已排序好的判断条件
		for(int i=array.length-1;i>0&&flag;i--) {
			flag=false;
			for(int j=array.length-1;j>0;j--) {
				if(array[j]<array[j-1]) {
					swap(array,j,j-1);
					flag=true;//每次执行了交换则flag为true,否则表示已排序直接中断循环;
				}
			}
		}
		return array;
	}
	public static void swap(int []array,int i,int j) {
		int temp=array[i];
		array[i]=array[j];
		array[j]=temp;
	}

2.2 选择排序

选择排序是表现最稳定的排序算法之一,在使用它的时候,数据规模越小越好。理论上讲,选择排序的实现比较简单,是大部分人能首先想到使用的一种算法。

  1. 原理
    首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。(也可以考虑同时选择最大值和最小值进行放置)。
  2. 代码实现
/**
	 * 选择排序
	 * <p>Title: selectionSort</p>  
	 * <p>Description: </p>  
	 * @param array
	 * @return
	 */
	public static int[] selectionSort(int []array) {
		if(array.length == 0)
			return array;
		for(int i=0;i<array.length;i++) {
			int minIndex=i;
			for(int j=i;j<array.length;j++) {
				if(array[minIndex]>array[j])
					minIndex=j;
			}
			swap(array,i,minIndex);
		}
		return array;
	}
	public static void swap(int []array,int i,int j) {
		int temp=array[i];
		array[i]=array[j];
		array[j]=temp;
	}

2.3 插入排序

  1. 原理
    插入排序(Insertion-Sort) 的算法描述是一种简单直观的排序算法。它的工作原理是假设前n-1个数是已经排好序的,然后将第n个数插入前面已经排好序的数列中,重复此过程直到插入完所有数。
  2. 代码实现
/**
	 * 插入排序
	 * <p>Title: insertionSort</p>  
	 * <p>Description: </p>  
	 * @param array
	 * @return
	 */
	public static int [] insertionSort(int []array) {
		for(int i=1;i<array.length;i++) {
			int temp=array[i];
			int index=i-1;
			while(index>=0 && temp<array[index]) {
				array[index+1]=array[index];
				index--;
			}
			array[index+1]=temp;
		}
		return array;
	}

2.4 希尔排序

希尔排序是一种改进的插入排序,但相对于插入排序的稳定,希尔排序是不稳定的,它是一种缩小增量排序,在交换元素位置时可能会打破已有的相同元素排序顺序。

  1. 原理
    希尔排序先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。(在这里我们选择增量gap=length/2),并以gap/=2的方式继续缩小增量。
  2. 代码实现
/**
	 * 希尔排序
	 * <p>Title: shellSort</p>  
	 * <p>Description: </p>  
	 * @param array
	 * @return
	 */
	public static int [] shellSort(int []array) {
		if(array.length<=1)
			return array;
		int len=array.length;
		int gap=len/2;
		while(gap>0) {
			for(int i=gap;i<len;i++) {
				int temp=array[i];
				int preIndex=i-gap;
				while(preIndex>=0 && temp<array[preIndex]) {
					array[preIndex+gap]=array[preIndex];
					preIndex-=gap;
					}
				array[preIndex+gap]=temp;
			}
			gap/=2;
		}
		return array;
	}

2.5 归并排序

归并排序需要使用额外数组进行数据的存储,是采用分治法的一个非常典型的应用。归并排序是一种稳定的排序方法,它是将两个有序的子序列合并,得到完全有序的序列。(熟悉递归调用非常容易理解,面试题里有出现过合并两个有序链表题目)

  1. 原理
    将待排序列分成两个子序列,并对每部分递归应用归并排序,在两部分都排好序后,对其进行合并。
  2. 代码实现
	public static int[] merge(int[]left,int[] right) {
		int[] result = new int[left.length+right.length];
		for(int index=0,i=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++];
		}
		return result;
	}
	/*
	 * 递归调用实现
	 */
	public static int[] mergeSort(int []array) {
		if(array.length<2)
			return array;
		int mid=array.length/2;
		int[] left=Arrays.copyOfRange(array, 0, mid);
		int[] right=Arrays.copyOfRange(array, mid, array.length);
		return merge(mergeSort(left),mergeSort(right));
	}

2.6 快速排序

快速排序是一个出题频率很高的题目,且在数据结构中是比较重要的排序之一。

  1. 原理
    该算法在数组中选择一个基准(pivot)元素,将数组分为两部分,使得一部分的元素都小于等于基准元素,另一部分的所有元素都大于基准元素,再对第一部分和第二部分分别递归应用快速排序算法,最终得到完全有序序列。
  2. 代码实现
	/**
	 * 快速排序
	 * <p>Title: quicklySort</p>  
	 * <p>Description: 填坑分治法</p>  
	 * @param arr
	 * @param low
	 * @param high
	 * @return
	 */
	public static int []quicklySort(int []arr,int low ,int high) {
		if(low<high) {
			int index=patition(arr,low,high);
			quicklySort(arr,low,index);
			quicklySort(arr,index+1,high);
		}
		return arr;
	}
	//找到序列分隔处
	public static int patition(int[] arr, int low ,int high) {
		int temp=arr[low];
		while(low<high) {
			while(low<high&& arr[high]>=temp) 
				high--;			
			arr[low] = arr[high];
			while(low<high&& arr[low]<temp) 
				low++;			
			arr[high] = arr[low];
		}
		arr[low]=temp;
		return low;
	}

2.7 堆排序

堆排序是指利用堆这种数据结构所设计的一种排序算法,堆积是一个近似完全二叉树的结构,同时需要满足:子节点的键值或索引总是小于(大于)它的父节点,在这里需要掌握二叉树相关知识。(对比了许多堆排序思想,整理了一个自己容易且理解较好的代码)

  1. 原理
    ①首先需要构建一个大顶堆(或者小顶堆),从最后一个非叶子节点开始比较,若其比它的子节点小,则交换(左子节点为i2+1,右子节点为i2+2)。
    ②依次将堆顶元素跟未交换的最后一个元素交换(若末尾元素已交换,则交换前一个未交换过的元素),使得末尾元素为当前最大值,得到新的无序区再调整称大顶堆,直至全部交换完毕。
  2. 代码实现
/**
	 * 数组实现堆排序
	 * <p>Title: adjustHeap</p>  
	 * <p>Description: 构造大顶堆</p>  
	 * @param array
	 * @param i
	 * @param length
	 */
public static void adjustHeap(int []array,int i,int length) {
		int temp=array[i];
		//节点的左节点索引为i*2+1:
		for(int k=i*2+1;k<length;k=k*2+1) {
			if(k+1<length&&array[k]<array[k+1])
				k++;
			if(array[k]>temp) {
				array[i]=array[k];
				i=k;
			}
			else break;
		}
		array[i]=temp;
			
	}
		/*
	 * 堆排序实现
	 */
	public static int[] HeapSort(int []array) {
		//1.构造大顶堆
		if(array.length<=1) return array;
		//len/2-1即为从最后一个非叶子节点开始构造
		for(int i=array.length/2-1;i>=0;i--)
			adjustHeap(array,i,array.length);
		//2.调整堆顶元素与末尾元素交换
		for(int j=array.length-1;j>0;j--) {
			swap(array,0,j);
			adjustHeap(array,0,j);//调整的最后一个元素即已经排序好,只需调整前j个元素
		}
		return array;
	}

2.8. 计数排序

计数排序的核心在于将输入的数据值转化为键值存储在额外的数组空间中,适合统计一定范围内相同数字出现的次数。

  1. 原理
    计数排序需要额外使用一个计数数组,其索引代表对应待排序数组中的数字出现的次数,然后将待排序数组的元素加入到数组之中,达到重新排序的效果。
  2. 代码实现
/**
	 * 计数排序
	 * <p>Title: CountSort</p>  
	 * <p>Description: </p>  
	 * @param array
	 * @return
	 */
	public static int []CountSort(int []array) {
		if(array.length<=1)
			return array;
		int min=array[0],max=array[0];
		for(int i=1;i<array.length;i++) {
			if(array[i]>max)
				max=array[i];
			if(array[i]<min)
				min=array[i];
		}
		int bias=0-min;//找到基准值
		int []buk=new int[max-min+1];//找到基准数组
		Arrays.fill(buk, 0);
		/**
		 * 对基准数组进行计数统计
		 */
		for(int i=0;i<array.length;i++) {
			buk[array[i]+bias]++;
		}
		int index=0,i=0;
		while(index<array.length) {
			if(buk[i]!=0) {
				array[index]=i-bias;
				buk[i]--;
				index++;
			}else
				i++;
		}
		return array;
	}

2.9 基数排序、桶排序

基数排序和桶排序跟计算排序类似,均用到了桶的概念,相对于计算排序,基数排序会根据键值的每位数字来分配桶,桶排序的每个桶存储一定范围的数值,更加灵活,在这里我就不写思想和代码实现了,如果大家感兴趣可以自己去实现下或者看看别人的思路,之后我还会继续更新一些其他的算法思路,包括力扣牛客算法题,同时我也会分享一下我的一些毕设论文思路,是关于语义位置隐私保护方向的。之前不太喜欢记录分享自己的一些东西,感觉现在也不是特别晚。

参考资料
超详细十大经典排序算法总结(java代码)
插入、选择、堆等七种常用排序算法的实现和优化(Java语言实现)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值