内排序_算法
概述
根据排序元素所在位置的不同,排序分: 内排序和外排序。
内排序:在排序过程中,所有元素调到内存中进行的排序,称为内排序。内排序是排序的基础。内排序效率用比较次数来衡量。按所用策略不同,内排序又可分为插入排序、选择排序、交换排序、归并排序及基数排序等几大类。
外排序:在数据量大的情况下,只能分块排序,但块与块间不能保证有序。外排序用读/写外存的次数来衡量其效率。
分类
图1
比较:需要比较两个元素的大小(前后)才能进行的排序。
插入:遍历到的元素放入之前维护的已完成排序的序列中。
交换:每次只调换两个元素之间的位置。
选择:选择剩余元素中最大或最小的元素。
稳定性
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
意义:排序的内容是一个复杂对象的多个数字属性,且其原本的初始顺序存在意义,那么需要在二次排序的基础上保持原有排序的意义,才需要使用到稳定性的算法。例如要排序的内容是一组原本按照价格高低排序的对象,如今需要按照销量高低排序,使用稳定性算法,可以使得想同销量的对象依旧保持着价格高低的排序展现,只有销量不同的才会重新排序。
比较类排序
交换排序
冒泡排序
冒泡排序对基本思想:通过无序区中相邻元素间关键字的比较和位置的交换,使关键字最小的元素如气泡一样逐渐上浮。
算法描述
- 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
- 针对所有的元素重复以上的步骤,除了最后一个;
- 重复步骤1~3,直到排序完成。
初始关键字 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|
i=0 | 0 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
i=1 | 0 | 1 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 |
i=2 | 0 | 1 | 2 | 9 | 8 | 7 | 6 | 5 | 4 | 3 |
i=3 | 0 | 1 | 2 | 3 | 9 | 8 | 7 | 6 | 5 | 4 |
i=4 | 0 | 1 | 2 | 3 | 4 | 9 | 8 | 7 | 6 | 5 |
i=5 | 0 | 1 | 2 | 3 | 4 | 5 | 9 | 8 | 7 | 6 |
i=6 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 9 | 8 | 7 |
i=7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 8 |
i=8 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
public static void buttleSort(int[] nums) {
for (int i = 0; i < nums.length - 1; i++) {
for (int j = 0; j < nums.length - 1; j++) {
if (nums[j] > nums[j + 1]) {
//两元素比较交换,升序
int tmp = nums[j + 1];
nums[j + 1] = nums[j];
nums[j] = tmp;
}
}
}
}
快速排序
快排是由冒泡排序改进而来,基本思想:在待排序的n个元素中任取一个座位基准,把该元素放入合适位置,数据序列被分为两部分,所有比该元素小的在前一部分,所有比该元素大的在后一部分。这个过程为一趟快速排序,然后在前后两部分内分别重复上述步骤。直至子表的长度为1或者0。
算法描述:
- 从数列中挑出一个元素,称为 “基准”(pivot);
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
- 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。
private static void quickSort(int[] nums, int left, int right) {
if (left < right) {
int partitionIndex = partition(nums, left, right);
quickSort(nums, left, partitionIndex - 1);
quickSort(nums, partitionIndex + 1, right);
}
}
private static int partition(int[] nums, int left, int right) {
int pivot = left;//基准值
int index = pivot + 1;
for (int i = index; i <= right; i++) {
if (nums[i] > nums[pivot]) {
//降序
int tmp = nums[i];
nums[i] = nums[index];
nums[index] = tmp;
index++;
}
}
int tmp = nums[pivot];
nums[pivot] = nums[index - 1];
nums[index - 1] = tmp;
return index - 1;
}
插入排序
插入排序
插入排序的思路:待排序列分为有序区和无序区,然后将无序区中的元素插入到有序区中合适的位置。
算法描述:
- 从第一个元素开始,该元素可以认为已经被排序;
- 取出下一个元素,在已经排序的元素序列中从后向前扫描;
- 如果该元素(已排序)大于新元素,将该元素移到下一位置;
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
- 将新元素插入到该位置后;
- 重复步骤2~5。
初始关键字 | [9] | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|
i=1 | [8 | 9] | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
i=2 | [7 | 8 | 9] | 6 | 5 | 4 | 3 |