排序大全-Java

本节总结几种常用的排序算法-冒泡排序、快速排序(递归和非递归)、归并排序(递归和非递归)、堆排序和优先队列。

本节代码以对一维数组排序为例,假设数组长度为n~


调用库排序

public class Sort {
	//调用库函数
	public int[] MySort(int[] arr){
		Arrays.sort(arr);
		return arr;
	}
	
	public static void main(String[] args) {
		int[] arr = {5,2,6,3,1,4};
		Sort s = new Sort();
		System.out.println(Arrays.toString(s.MySort(arr)));		
	}

}

方法简单,但是面试的时候可能会被秒挂~


冒泡排序

这个算法名字的由来是因为越小的元素经由交换慢慢浮到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。

冒泡排序算法的原理如下:

1、对于未排序数组依此比较相邻元素,如果前一个比后一个大,就交换他们两个,从开始第一对到结尾最后一对,一次遍历后会选出最大的数放在未排序数组的最后的位置,相当于数组未排序的长度减1,数组已排序的长度加1;

2、二次遍历对未排序数组重复步骤1,仍然依次比较相邻元素,选出最大的数放在未排序数组的最后的位置,数组未排序的长度再次减1,数组已排序的长度加1;

    ......

3、总共需要遍历数组n次,这时数组未排序的长度变成0,数组已排序的长度变成n,数组排好序。

所以冒泡排序需要两层循环,一层外循环控制遍历数组长度次,一层内循环控制对未排序数组的遍历比较。

public class Sort {

     //每次遍历在未排序的数组中选出最大的

    public int[] BubbleSort(int[] arr){
		
		for(int i=0;i<arr.length;i++){
			for(int j=0;j<arr.length-i-1;j++){//未排序数组的长度在不断减少
				if(arr[j]>arr[j+1]){
					swap(arr, j, j+1);
				}
			}
			System.out.println(Arrays.toString(arr));//打印每一次遍历的结果
		}
		return arr;
	}

  //交换数组中的两个元素
    public void swap(int[] arr,int i,int j){
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	 }

    public static void main(String[] args) {
		int[] arr = {5,2,6,3,1,4};
		Sort s = new Sort();
		System.out.println(Arrays.toString(s.BubbleSort(arr)));
			
	}
}

快速排序

快速排序的思想是每次排序根据基准把数组分成两部分,大于基准的一部分移到数组的右边,小于基准的一部分移到数组左边,然后在左右两边再次选定基准元素递归进行排序,以达到整个序列有序。

快速排序算法的原理如下:

1、设置两个变量,left、right,排序开始时:left = 0,right = n-1;

2、找到数组基准正确位置,所有元素比基准值小的摆放在基准前面,所以元素比基准大的摆放在基准的后面;

3、依次递归调用基准点前的子数组和基准点后的子数组排序;

4、得到最终排序好的数组。

public class Sort {

	//快速排序,选择一个基准,一次排序把大于基准的放在右边,小于基准的放在左边
	public int[] quickSort(int[] arr,int left,int right){
		if(left<right){
			int partition = partition(arr, left,right);
			quickSort(arr,left,partition-1);
			quickSort(arr, partition+1, right);
		}
		return arr;
		
	}
	public int partition(int[] arr,int left,int right){
		int tmp = arr[left];
		while(left<right){
			while(left<right&&arr[right]>=tmp){
				right--;
			}
			swap(arr, left, right);
			while(left<right&&arr[left]<=tmp){
				left++;
			}
			swap(arr,left,right);
			System.out.println(Arrays.toString(arr));
		}
		return left;
	}
	//快排非递归
	public int[] nonRec_quickSort(int[] arr,int left,int right){
		Stack<Integer> stack = new Stack<>();
		if(left<right){
			stack.push(right);
			stack.push(left);
			while(!stack.isEmpty()){
				int l = stack.pop();
				int r = stack.pop();
				int index = partition(arr, l, r);//找到分割点
				if(l<index-1){//在左边继续找分割点
					stack.push(index-1);
					stack.push(l);
				}
				if(r>index+1){//在右边继续找分割点
					stack.push(r);
					stack.push(index+1);
				}
			}
		}
		return arr;
	}
	
	public void swap(int[] arr,int i,int j){
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	public static void main(String[] args) {
		int[] arr = {5,2,6,3,1,4};
		Sort s = new Sort();
		System.out.println(Arrays.toString(s.quickSort(arr, 0, arr.length-1)));	
        System.out.println(Arrays.toString(s.nonRec_quickSort(arr, 0, arr.length-1)));		
	}

}

归并排序

归并排序是采用分治算法的思想,先把要排序的数组划分为两份,然后再把子数组再次二分,直到数组的大小为1,然后依次两两合并、四四合并,不断地向上合并,得到最终的排序结果。

归并排序的算法原理如下:

1、设置两个变量,left、right,排序开始时:left = 0,right = n-1;

2、设置中间变量mid,把数组划分为两份,两份再划为四份,直到数组的大小为1;

3、把left->mid和mid->right两两进行依次合并,然后再四四合并......;

4、得到排序后的结果。

public class Sort {
	
	//归并排序,不断二次分割,然后合并
	public int[] mergeSort(int[] arr,int left,int right){
		if(left==right){
			return arr;
		}
		int mid = left+(right-left)/2; 
		mergeSort(arr, left, mid);
		mergeSort(arr, mid+1, right);
		merge(arr,left,mid,right);
		return arr;
	}
	public void merge(int[] arr,int left,int mid,int right){
		int[] temp = new int[right-left+1];
		int i=0;
		int p1 = left;
		int p2 = mid+1;
		while(p1<=mid&&p2<=right){
			temp[i++] = arr[p1]<arr[p2]?arr[p1++]:arr[p2++];
		}
		while(p1<=mid){
			temp[i++] = arr[p1++];
		}
		while(p2<=right){
			temp[i++] = arr[p2++];
		}
		for(i=0;i<temp.length;i++){
			arr[left+i] = temp[i];
		}
	}
	
	//归并非递归,先合并最近的两个,然后再四个,8个
	
		public int[] mergeSortNonRecursive(int[] arr){
			int len = 1;
			int low = 0;
			int mid;
			int high;
			while(len<=arr.length){
				for(int i=0;i+len<=arr.length;i+= len*2){
					low = i;
					mid = i+len-1;
					high = i+len*2-1;
					if(high>arr.length-1){
						high = arr.length-1;
					}
					Merge(arr, low, mid, high);
				}
				len += len;
			}
			return arr;
		}
	
	public void swap(int[] arr,int i,int j){
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	public static void main(String[] args) {
		int[] arr = {5,2,6,3,1,4};
		Sort s = new Sort();
		System.out.println(Arrays.toString(s.mergeSort(arr, 0, arr.length-1)));
		
	}

}

堆排序

堆是一种近似完全二叉树的结构,常用的有大根堆(根节点的值最大)、小根堆(根节点的值最小),堆排序是利用堆这种数据结构所设计的一种排序算法。

下面例子中是利用大根堆进行排序

思路如下:

1、给定数组arr,利用该数组构造完全二叉树--根节点最大,即arr[0]位置最大,把arr[0]与arr[n-1]交换,即把最大值放在n-1的位置上;

2、交换以后arr[0]不再满足大根堆的要求,需要把数组arr从0到n-2的位置重新构建大根堆,做法就是通过与子节点比较交换移动,构建新的大根堆;

3、再次交换arr[0]与arr[n-2],把新的最大值放在n-2的位置上;

     ......

4、重复上述步骤,得到最终的排序数组。

public class Sort {
	
	//堆排序
    //思路是交换根结点和尾结点,大根堆的根结点就是数组的最大值,可以直接放在堆尾,
	//将堆范围缩小,然后将缩小后的堆重新调整尾大根堆
	//(相当于每次挑出根,进行交换,然后把剩下的重新排成大根堆)
	//依次交换和拿出根
	public int[] HeapSort(int[] arr){
		if(arr==null||arr.length<2){
			return arr;
		}
		for(int i=arr.length/2-1;i>=0;i--){
			heapify(arr, arr.length,i);
		}
		for(int i=arr.length-1;i>=0;i--){
			swap(arr, 0, i);
			heapify(arr, i, 0);
		}
		return arr;
	}
    //新的节点加入时
    public void heapify(int[] arr,int n,int index){
		int tmp = arr[index];
		int t = index*2;
		while(t+1<n){
			if(t+1<n&&arr[t]<arr[t+1]){
				t++;
			}
			if(arr[t]>tmp){
				arr[index] = arr[t];
				index = t;
				t = index*2;
			}else{
				break;
			}
			arr[index] = tmp;
		}
	}
	public static void main(String[] args) {
		int[] arr = {5,2,6,3,1,4};
		Sort s = new Sort();
		System.out.println(Arrays.toString(s.HeapSort(arr)));		
	}

}

优先级队列

普通的队列是一种先进先出的数据结构,元素在队尾添加,从队头删除,在优先队列中,元素被赋予了优先级,当访问元素队列时,具体最高优先级的元素最先删除,通常采用堆数据结构来实现。

优先级队列算法的思路如下:

1、定义好优先级队列是升序还是降序;

2、把数组依次加入到优先级队列中;

3、依次弹出元素(按优先级)放在原数组中。

public class Sort {
	
	//优先级队列
	//优先队列不再遵循先入先出的原则,而是分为两种情况:
	//最大优先队列,无论入队顺序,当前最大的元素优先出队
	//最小优先队列,无论入队顺序,当前最小的元素优先出队
	//优先级队列,也叫二叉堆、堆的本质上是一种完全二叉树
	//大根堆:树中每个非叶子结点都不大于其左右孩子结点的值,也就是根结点最小的堆
	//小根堆:树中每个非叶子结点都不小于其左右孩子结点的值,也就是根结点最大的堆
	public int[] PriorityQueue(int[] arr){
		PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {
		@Override
		public int compare(Integer o1, Integer o2) {
			// TODO Auto-generated method stub
			return o1-o2;//升序
			//return o1.compareTo(b);
		}
		});
		for(int i=0;i<arr.length;i++){
			queue.add(arr[i]);
		}
		int[] newarr = new int[arr.length];
		for(int i=0;i<arr.length;i++){
			newarr[i] = queue.poll();
		}
		return newarr;
	}
	
	public static void main(String[] args) {
		int[] arr = {5,2,6,3,1,4};
		Sort s = new Sort();	
		System.out.println(Arrays.toString(s.PriorityQueue(arr)));
		
	}

}

总结

本节课主要使用Java实现几种常用的排序算法,如果你对一些排序的过程不理解,这篇笔记可能会帮助到你。

个人总结一下,方便以后学习。

欢迎交流~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值