交换排序(冒泡、快排)(java)

交换排序: 将排序表中两个记录的关键码比较,若与排序要求相逆,则将两者交换。

一、.冒泡排序

1.基本思想:对待排序序列从前往后,依次比较相邻元素的排序码,若发现逆序则交换,使排序码较大的元素逐渐从前部移向后部。

2.代码结果:

排序之前:
[9, -16, 21, 23, -30, -49, 21, 30, 30]
开始排序
[-16, 9, 21, -30, -49, 21, 23, 30, 30]
[-16, 9, -30, -49, 21, 21, 23, 30, 30]
[-16, -30, -49, 9, 21, 21, 23, 30, 30]
[-30, -49, -16, 9, 21, 21, 23, 30, 30]
[-49, -30, -16, 9, 21, 21, 23, 30, 30]
[-49, -30, -16, 9, 21, 21, 23, 30, 30]
排序之后:
[-49, -30, -16, 9, 21, 21, 23, 30, 30]

3.图示:

4.效率分析:

从原始冒泡算法可以看出,

待排序元素是正序时,只进行 1 次循环,比较 n-1 次,移动元素次数为 0 次;

待排序元素是逆序时,需要进行 n-1 次循环,比较 (n^2-n)/2 次,移动元素次数为 3*(n^2-n)/2 次;

所以,时间复杂度为O(n^2);由于移动元素过多,是内排序中速度较慢的一种;因为冒泡排序只进行元素间的顺序移动,所以是一个稳定的算法。

5.测试代码:

    原始代码:

public class BubbleSort {
	public static void bubbleSort(int[] data) {
		System.out.println("开始排序");
		int arrayLength = data.length;
		for (int i = 0; i < arrayLength - 1; i++) {
			for (int j = 0; j < arrayLength - 1 - i; j++) {
				if (data[j] > data[j + 1]) {
					int temp = data[j + 1];
					data[j + 1] = data[j];
					data[j] = temp;
				}
			}
			System.out.println(java.util.Arrays.toString(data));
		}
	}

	public static void main(String[] args) {
		int[] data = { 9, -16, 21, 23, -30, -49, 21, 30, 30 };
		System.out.println("排序之前:\n" + java.util.Arrays.toString(data));
		bubbleSort1(data);
		System.out.println("排序之后:\n" + java.util.Arrays.toString(data));
	}
}

优化一:增加标记,如果在j=0 到 i 之间没有发生交换,则标记为true,说明该区间序列已有序,减少不必要比较,提高效率。


	//优化1
	public static void bubbleSort1(int[] data) {
		System.out.println("开始排序");
		int arrayLength = data.length;
		for (int i = 0; i < arrayLength - 1; i++) {
			boolean flag = false;
			for (int j = 0; j < arrayLength - 1 - i; j++) {
				if (data[j] > data[j + 1]) {
					int temp = data[j + 1];
					data[j + 1] = data[j];
					data[j] = temp;
					flag = true;
				}
			}
			System.out.println(java.util.Arrays.toString(data));
			if (!flag)
				break;
		}
	}

优化二:记录每一次循环交换的最后一个数的位置,记录该位置,下一次检索到该位置即可(因为该位置到最后位置的序列已有序)。

	//优化2
	public static void bubbleSort2(int[] data) {
		System.out.println("开始排序");
		int arrayLength = data.length;
		int i=arrayLength-1;
		int pos=0;
		while(i>0) {

			for (int j = 0; j <i; j++) {
				if (data[j] > data[j + 1]) {
					pos=j;
					int temp = data[j + 1];
					data[j + 1] = data[j];
					data[j] = temp;
				}
			}
			System.out.println(java.util.Arrays.toString(data));
			i=pos;
		}
	}

还有其它优化的方式,这里只记录理解和写法比较容易的几种。

二、.快速排序(重点)(分区交换排序)

是至今为止,所有内排算法中速度最快的一种

1.基本思想:任取待排序序列中的某个元素作为标准(也称为支点,界点,一般取第一个元素),通过一次划分,将待排元素分为左右两个子序列,左子序列元素的排序码均小于基准元素的排序码,右子序列的排序码均大于或等于基准元素的排序码,然后分别对两个子序列继续进行划分,直至每个序列只有一个元素为止,最后得到的序列便是有序序列。

2.图示:

3.一次划分过程:

1.low指向待划分区域首元素,high指向待划分区域尾元素:

2.R[0]=R[low] (为了减少数据的移动将作为标准的元素暂存
到R[0]中,最后再放入最终位置)

3.high从后往前移动直到R[high].key<R[0]key;

4. R[low]=R[high], low++

5.low从前往后移动直到R[low].key>=R[0].key;

6. R[high]=R[low], high--

7. goto 3

8.直到 loW==hgh 时,R[low]=R[0](即将作为标准的元素放到
其最终位置)

概括地说,一次划分就是从表的两端交替地向中间进行扫描
将小的放到左边,大的放到右边,作为标准的元素放到中间。

4.效率分析:

5.测试代码:

public class QuickSort0 {
	private static void swap(int[] data, int i, int j) {
		int temp = data[i];
		data[i] = data[j];
		data[j] = temp;
	}

	private static void subSort(int[] data, int start, int end) {
		if (start < end) {
			int base = data[start];
			int low = start;
			int high = end + 1;
			while (true) {
				while (low < end && data[++low] - base <= 0)
					;
				while (high > start && data[--high] - base >= 0)
					;
				if (low < high) {
					swap(data, low, high);
				} else {
					break;
				}
			}
			swap(data, start, high);
			
			subSort(data, start, high - 1);//递归调用
			subSort(data, high + 1, end);
		}
		System.out.println(java.util.Arrays.toString(data));
	}
	public static void quickSort(int[] data){
		subSort(data,0,data.length-1);
	}
	
	
	public static void main(String[] args) {
		int[] data = { 9, -16, 30, 23, -30, -49, 25, 21, 30 };
		System.out.println("排序之前:\n" + java.util.Arrays.toString(data));
		System.out.println("开始排序");
		quickSort(data);
		System.out.println("排序之后:\n" + java.util.Arrays.toString(data));
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41048982/article/details/109336728
今日推荐