常见排序算法 JAVA代码

一:冒泡排序

算法描述:

        首先从数组的第一个元素开始到数组最后一个元素为止,对数组中相邻的两个元素进行比较,如果位于数组左端的元素大于数组右端的元素,则交换这两个元素在数组中的位置,此时数组最右端的元素即为该数组中所有元素的最大值。接着对该数组剩下的n-1个元素进行冒泡排序,直到整个数组有序排列。算法的时间复杂度为O(n^2)。是一个稳定的算法。

//冒泡排序  遇到比自己大的则交换 把最大 次大 次次大.....分别确定好
	public static void bubbleSort(int []arr) {
		int temp = 0;
		for(int i = 0;i < arr.length - 1;i ++) {
			boolean flag = true;
			for(int j = 0;j < arr.length - 1 - i;j ++) {
				if(arr[j] > arr[j + 1]) {
					flag = false;
					temp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = temp;
				}
			}
			if(flag) break;
		}
	}

二:直接选择排序 :

算法描述:

每一趟在n-i+1(i=1,2,...,n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。算法的时间复杂度为O(n^2)。是一个不稳定的算法。举个例子:序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了

//选择排序:依次选择最小的放在第一位 第二位....
	public static void selectSort(int []arr) {
		for(int i = 0;i < arr.length - 1;i ++) {
			int idx = 0,min = Integer.MAX_VALUE;
			for(int j = i;j < arr.length;j ++) {
				if(arr[j] < min) {
					min = arr[j];
					idx = j;
				}
			}
			int temp = arr[i];
			arr[i] = arr[idx];
			arr[idx] = temp;
		}
	}

三:插入排序


算法描述

将无序序列插入到有序序列中。算法的时间复杂度为O(n^2)。是一个稳定的算法。

//插入排序 从已排序的最后一个数字开始比较 比自身大的数向后挪一位,直到找到合适位置则插入
	public static void insertSort(int []arr) {
		for(int i = 1;i < arr.length;i ++) {
			int cur = arr[i];
			int idx = i - 1;
			while(idx >= 0 && arr[idx] > cur) {
				arr[idx + 1] = arr[idx];
				idx --;
			}
			arr[idx + 1] = cur;
		}
	}

四:快速排序

算法描述:

       通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,已达到整个序列有序。

       一趟快速排序的具体过程可描述为:从待排序列中任意选取一个记录(通常选取第一个记录)作为基准值,然后将记录中关键字比它小的记录都安置在它的位置之前,将记录中关键字比它大的记录都安置在它的位置之后。这样,以该基准值为分界线,将待排序列分成的两个子序列。时间复杂度为O(nlogn)。是一个不稳定的算法。

//快速排序:先让数组部分有序(左部分小于右部分),再递归调用对左右两部分分别进行快速排序。
	public static void quickSort(int []arr,int left,int right) {
		if(left > right) return;
		//选一个基准值
		int base = arr[left];
		//定义变量i指向最左边,j指向最右边
		int i = left,j = right;
		while(i != j) {
			//从右到左找第一个比基准值小的数
			while(i < j && arr[j] >= base) j --;
			//从左到右找第一个比基准值大的数
			while(i < j && arr[i] <= base) i ++;
			//找到后进行交换
			int temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
		//i 和 j相遇,交换基准值与相遇位置的值
		arr[left] = arr[i];
		arr[i] = base;
		
		//对左右两部分进行快速排序
		quickSort(arr,left,i - 1);
		quickSort(arr,i+1,right);
	}

五:归并排序

算法描述:

       “归并”的含义是将两个或两个以上的有序序列组合成一个新的有序表。假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并如此重复,直到得到一个长度为n的有序序列。时间复杂度为O(nlogn)。是一个稳定的算法。

//归并排序:自顶向下递归使部分有序,再使自底向上merge使得部分有序变成整体有序
	
	public static void _merge(int []arr,int left,int mid,int right) {
		//复制原数组 便于把结果数组直接放入原数组中
		int []temp = new int [right - left + 1];
		for(int i = left;i <= right;i ++) {
			temp[i - left] = arr[i];
		}
		// i指向左部分有序数组的第一个元素   
		// j指向右部分有序数组的第一个元素
		// k指向元素组的第一个位置 每次将当前的最小元素放到位置k
		int i = left,j = mid + 1;
		for(int k = left;k <= right;k ++) {
			if(i > mid) {//左数组已经取完 直接取右数组
				arr[k] = temp[j - left];
				j ++;
			}else if(j > right) {//右数组已经取完 直接取左数组
				arr[k] = temp[i - left];
				i ++;
			}else if(temp[i - left] < temp[j - left]) {//左右两数组均有元素 取最小值
				arr[k] = temp[i - left];
				i ++;
			}else {
				arr[k] = temp[j - left];
				j ++;
			}
		}
	}
	public static void mergeSort(int []arr,int left,int right) {
		if(left >= right) return;
		int mid = (left + right) >> 1;
		//把数组分为左右两部分 直到数组部分有序(只有一个元素)
		mergeSort(arr,left,mid);
		mergeSort(arr,mid+1,right);
		_merge(arr,left,mid,right); //自底向上归并左右两个有序数组
	}

六:堆排序

算法描述:

       堆看做是一个完全二叉树。并且,每个结点的值都大于等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于等于其左右孩子结点的值,称为小顶堆。 

      堆排序(Heap Sort)是利用堆进行排序的方法。其基本思想为:将待排序列构造成一个大顶堆(或小顶堆),整个序列的最大值(或最小值)就是堆顶的根结点,将根节点的值和堆数组的末尾元素交换,此时末尾元素就是最大值(或最小值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值(或次小值),如此反复执行,最终得到一个有序序列。时间复杂度为O(nlogn)。是一个不稳定的算法。

// 堆排序
	
	//heapify 使得当前节点作为根节点的树成为一个堆
	public static void heapify(int []tree,int n,int idx) {
		if(idx >= n) return;
		//比较当前节点与左右儿子的大小
		int left = 2 * idx + 1;
		int right = 2 * idx + 2;
		int max = idx;
		if(left < n && tree[left] > tree[max]) max = left;
		if(right < n && tree[right] > tree[max]) max = right;
		
		if(max != idx) {
			int temp = tree[idx];
			tree[idx] = tree[max];
			tree[max] = temp;
			heapify(tree,n,max);
		}
	}
	public static void build_heap(int []tree) {
		int n = tree.length - 1;
		int lastParent = (n - 1) / 2;
		//从最后一个父节点开始 分别向前对所有节点做一次heapify
		for(int i = lastParent;i >= 0;i --) {
			heapify(tree,n,i);
		}
	}
	public static void heapSort(int []tree) {
		//使数组形成一个堆
		build_heap(tree);
		for(int i = tree.length - 1;i >= 0;i --) {
			// 堆顶为最大值 每次把堆顶与最后一个值交换 即保存在最后一位
			int temp = tree[0];
			tree[0] = tree[i];
			tree[i] = temp;
			//交换后 进行heapify操作形成一个新的堆
			//砍掉后边已排好序的部分
			heapify(tree,i,0);
		}
	}
	


 

 最后,对算法的稳定性做一个总结:

稳定:冒泡排序、插入排序、归并排序和基数排序

不稳定:选择排序、快速排序、希尔排序、堆排序 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值