经典排序算法之插入排序和快速排序

1.插入排序

    插入排序的基本操作是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序。基本思想为,将待排序的数据分为两部分,一部分是有序的,另一部分的每个元素将在有序的这一部分找到合适的位置插入即可,如图所示:

                                            

时间复杂度:如果想把n个元素的序列升序排列,那么采用插入排序存在最好情况和最坏情况。最好情况就是,序列已经是升序排列了,在这种情况下,需要进行的比较操作需(n-1)次即可。最坏情况就是,序列是降序排列,那么此时需要进行的比较共有n(n-1)/2次。插入排序的赋值操作是比较操作的次数加上 (n-1)次。平均来说插入排序算法的时间复杂度为O(n^2)。因而,插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,例如,量级小于千,那么插入排序还是一个不错的选择。

示例代码:

public class InsertionSort {
	
	public static void main(String[] args) {
		int arr[] = {5, 1, 7, 3, 1, 6, 9, 4};
		insertionSort(arr);
	}

	static void insertionSort(int arr[]) {
		int temp = 0;
		//后面的元素
		for (int i = 1; i < arr.length; i++) {
			//将后面的元素与前面的元素进行比较
			for (int j = i; j > 0; j--) {
				if(arr[j] < arr[j - 1]) {
					temp = arr[j];
					arr[j] = arr[j - 1];
					arr[j - 1] = temp;
				}else {
					break;
				}
			}
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
	}
}

2.快速排序(重要)

    快速排序既不浪费空间速度又快,快速排序是通过一轮的排序将序列分割成独立的两部分,其中一部分序列的基准点(这里主要用值来表示)均比另一部分基准点小。继续对长度较短的序列进行同样的分割,最后到达整体有序。在排序过程中,由于已经分开的两部分的元素不需要进行比较,故减少了比较次数,降低了排序时间。

    下面通过示例做进一步说明:

    假设我们对23,15,30,35,28,12,50,2进行排序,则排序过程如下:

    原始数据:23,15,30,35,28,12,50,2,假设我们选择23为关键字,i = 0,j = 7,i和j为数组的下标。

    一定要从右边开始,首先2小于23,此时i++,i=1。

    15比23小,i继续加,继续往前找,找到30(i=2)比23大,将30与2进行交换:

    23,15,2,35,28,12,50,30

    此时j--,找到12(j=5)比23小;然后i++找到35(i=3)比23大,将12和35交换:

    23,15,212,28,35,50,30

    此时j--,当j=i时,结束本次排序,再将23归位:

    即23与12(i=3)进行交换:

    12,15,223,28,35,50,30

    接着以23为基准点,将左右分为两段数据12,15,2和28,25,50,30。

    对这两段数据进行如上步骤的操作,如:假设对12,15,2排序,以12为基准点,则第一次:12,2,15。然后归位:

     2,12,15即可,另一段数据不再列举。

    依次类推,直到不可拆分出新的子序列为止。

    时间复杂度:

    快速排序是对冒泡排序的改进,快速排序之所比较快,因为相比冒泡排序,每次交换是跳跃式的。每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样每次只能在相邻的数之间进行交换,交换的距离就大的多了。因此总的比较和交换次数就少了,速度自然就提高了。当然在最坏的情况下,最坏情况发生在每次划分过程产生的两个区间分别包含n-1个元素和1个元素的时候,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和冒泡排序是一样的都是O(N2),它的平均时间复杂度为O(NlogN)。(最好情况:每次划分过程产生的区间大小都为n/2)。另外,快速排序不是稳定的。

示例代码:

public class QuickSort {

	public static void main(String[] args) {
		int arr[] = {23, 15, 30, 35, 28, 12, 50, 2};
		quickSort(arr, 0, 7);
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
	}
	
	static void quickSort(int arr[], int left, int right) {
		
		int i = left;
		int j = right;
		int key = arr[left];
		
		while(i < j) {
			//右边找小的
			while (arr[j]>=key && i<j) {
				j--;
			}
			//左边找大的
			while (arr[i]<=key && i<j) {
				i++;
			}
			//交换
			if(i<j) {
				int temp = arr[i];
				arr[i] = arr[j];
				arr[j] = temp;
			}
		}
		arr[left] = arr[i];
		arr[i] = key;
		//递归调用,对左边进行排序
		if(i > left) {
			quickSort(arr, left, i-1);
		}
		//递归调用,对右边进行排序
		if(j < right) {
			quickSort(arr, i+1, right);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/m0_38075425/article/details/81703676