一、排序基本概念
1、什么是排序?
排序就是将一个任意序列的一组数据,按某个关键字,重新排列为有序的序列。
2、内部排序和外部排序
内部排序:内部排序就是整个排序过程在内存储器中进行。
外部排序:简单来说,就是数据量太大。内存储器容量装不下,需要借助外部设备,这类排序就是外部排序。
3、稳定排序
稳定排序:如果在某个序列中存在多个具有相同关键字的元素。
在排序之后,他们的相对位置没有发生改变。相对位置就是:排序前在前面的依然在前面,在后面的依然在后面。
非稳定排序:与稳定排序的差别就在于具有相同关键字的元素,在排序后他们的相对位置是否发生改变。为稳定排序,相对位置是发生了改变的。
举例:
排序前:{1,2,3,4,7,3,7}
排序后:{1,2,3,3,4,7,7},这就是稳定排序,相对位置没有发生改变。
排序后:{1,2,2,3,3,4,7,7},这就是非稳定排序,相对位置发生改变。
4、排序类型
排序一般是八大排序类型,一下是七种,还有一种是插入排序中的折半插入排序。
5、排序效率
时间复杂度最高的是三种基本排序,建议优先掌握:直接排序,简单选择,冒泡排序。 还有一个快速排序也需要掌握,面试经常会问。
二、交换排序
1、冒泡排序
冒泡排序算法的原理如下:
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
public static void bubbleSort(int []arr) {
for(int i=0;i<arr.length;i++) {
for(int j=0;j<arr.length-i;j++) {
if(arr[j]>arr[j+1]) {
int temp = arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
2、快速排序
快速排序是冒泡排序的改进版。
快速排序主要思路:冒泡 + 分治 + 递归
1、先从序列中选出一个数作为基准数(一个第一个,简单)
2、分区过程,将每个比基准数小的放到左边,每个比基准数大的放到右边。
3、递归:在重新对左、右、区间进行第一、第二步操作、直到区间只有一个数,
代码测试
package com.gwz.datastructure.sort;
import java.util.Arrays;
/**
* 快速排序
*/
public class TestQuickSort {
/**
* 方法实现
* @param arr
*/
private static void quickSort(int[] arr) {
int low = 0;
int high = arr.length - 1;
quickSort(arr,low,high);
}
/**
* 递归
* @param arr
* @param low
* @param high
*/
private static void quickSort(int[] arr,int low ,int high) {
if (low < high) {
int index = partition(arr, low, high);
// 对、左、右、分区进行递归操作。
quickSort(arr, low, index - 1);
quickSort(arr, index + 1, high);
}
}
/**
* 分区
* @param arr
* @param low
* @param high
*/
private static int partition(int[] arr, int low, int high) {
int i = low;
int j = high;
int x = arr[i]; // 定义集准数
while (i < j ){
// 右边的指针左移,找到小于基准数的元素
while (i < j && arr[j] >= x ){
j--;
}
if (i < j) {
arr[i] = arr[j];
}
// 左边的指针右移,找到大于基准数的元素
while (i < j && arr[i]<= x) {
i++;
}
if (i < j) {
arr[j] = arr[i];
}
}
arr[i] = x;
return i;
}
public static void main(String[] args) {
int[] arr = {54,2,3,52,56,2,6,67,687};
// 排序前
System.out.println(Arrays.toString(arr));
// 快速排序
quickSort(arr);
// 排序后
System.out.println(Arrays.toString(arr));
}
}
三、选择排序
选择排序法的第一层循环从起始元素开始选到倒数第二个元素,主要是在每次进入的第二层循环之前,将外层循环的下标赋值给临时变量,接下来的第二层循环中,如果发现有比这个最小位置处的元素更小的元素,则将那个更小的元素的下标赋给临时变量,最后,在二层循环退出后,如果临时变量改变,则说明,有比当前外层循环位置更小的元素,需要将这两个元素交换.
public static void selectionSort(int[] arr){
for (int i = 0; i < arr.length - 1; i++) {
int min = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[min] > arr[j]) {
min = j;
}
}
if (min != i) {
int tmp = arr[min];
arr[min] = arr[i];
arr[i] = tmp;
}
}
}
四、插入排序
插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法 。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。
在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动 。
public class Insertion
{
public static void sort(Comparable[] a)
{
//将a[]按升序排列
int N=a.length;
for (int i=0; i<N; i++)
{
//将a[i]插入到a[i-1],a[i-2],a[i-3]……之中
for(j=i; j>0 && Comparable(a[j], a[j-1])<0; j--)
{
Comparable temp=a[j];
a[j]=a[j-1];
a[j-1]=temp;
}
}
}
}