排序算法(Sort Algorithm)
排序算法介绍和分类
将一组数据,依指定顺序进行排列
排序的分类
-
内部排序
指将需要处理的所有数据都加载到内部存储器中进行排序
-
外部排序
数据量过大,无法全部加载到内存中,需借助外部存储进行排序
常见的排序算法
冒泡排序(Bubble Sort)
基本思想
通过对待排序序列从前向后(从下表较小的元素 开始),依次比较相邻元素的值,若发现逆序,交换相邻元素的值
基本代码
public static void bubbleSorting(int[] arr){
for (int i = 0; i < arr.length-1; i++) {
for (int j = 0; j < arr.length-i-1; j++) {
if (arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
优化
因为排序过程 中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,,因此要在排序过程中设置一个标志flag判断元素是否交换,从而减少不必要的比较
优化后代码
public static void bubbleSorting(int[] arr){
int temp = 0;
//标志变量,表示是否进行过交换
boolean flag = false;
for (int i = 0; i < arr.length-1; i++) {
for (int j = 0; j < arr.length-i-1; j++) {
if (arr[j]>arr[j+1]){
flag = true;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
if (flag = false){//在一趟排序中一次都没有交换
break;
}else {
flag = false;//重置flag进行下次判断
}
}
// for (int i = 0; i < arr.length; i++) {
// System.out.print(arr[i]);
// }
// System.out.println();
}
选择排序(Select Sort)
基本思想
第一次从arr[0]~arr[n-1]中选取最小值,与arr[0]交换,然后一次从后面的数据选取最小值,与数组前的值交换
public static void selectSorting(int[] arr){
for (int i = 0; i < arr.length-1; i++) {
int temp = arr[i];
for (int j = i; j < arr.length; j++) {
if (arr[i]>arr[j]){//从小到大排序
temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
}
System.out.println();
}
插入排序(Insert Sort)
基本思想
插入排序属于内部排序,是对于排序的元素以插入的方式 找寻该元素的适当位置,以达到排序的目的
把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序吗一次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,是指成为新的有序表。
代码实现
public static void insertionSorting(int[] arr){
int insert = arr[0];//第一个插入的数,直接插入
int insertIndex = 0;//arr[1]起那面这个数的下标
arr[insertIndex] = insert;
for (int i = 1; i < arr.length-1; i++) {
//insertIndex >= 0,保证给insert找插入位置时不越界
//insert < arr[insertIndex,待插入的数即arr[insertIndex]后移
insert = arr[i];
insertIndex = i - 1;
while (insertIndex >= 0 && insert < arr[insertIndex]){
arr[insertIndex+1] = arr[insertIndex];
insertIndex--;
}
arr[insertIndex+1] = insert;
}
System.out.println(Arrays.toString(arr));
}
问题
-
若数据过于小,后移的次数较多影响效率
希尔排序(Shell Sort)
-
希尔排序是简单排序改进后更高效的排序
-
也称缩小增量排序
基本思想
-
把记录按下标的一定增量分组
-
对每组使用直接插入排序算法
-
随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法终止
交换式算法实现
/**
* 交换法,实现希尔排序,效率低
* @param arr
*/
public static void shellSortExchange(int[] arr){
//将数据根据数组长度进行分组
int len = (int) Math.floor(arr.length/2);
int temp = 0;
while (len>=1){
for (int i = len; i < arr.length; i++) {
//遍历各组所有的元素,(共有len组,每组2个元素),步长len
for (int j = i-len; j >= 0; j -= len) {
//从小到大排序
//如果当前元素大于加上步长的元素,需要交换
if (arr[j] > arr[j+len]){
temp = arr[j];
arr[j] = arr[j+len];
arr[j+len] = temp;
}
}
}
len = (int) Math.floor(len/2);
}
System.out.println(Arrays.toString(arr));
}
移位式算法实现
/**
* 移位式,效率高
* @param arr
*/
public static void shellSortShift(int[] arr){
int len = (int) Math.floor(arr.length/2);
int temp = 0;
//增量len,并逐步缩小增量
while (len >= 1){
//从第len个元素,诸葛对其所在的组进行直接插入排序
for (int i = len; i < arr.length; i++) {
int j = i;
temp = arr[j];
if (arr[j]<arr[j-len]){
while (j-len >= 0 && temp < arr[j-len]){
//移动
arr[j] = arr[j-len];
j -= len;
}
//退出循环后找到了插入的位置
arr[j] = temp;
}
}
len = (int) Math.floor(len/2);
}
System.out.println(Arrays.toString(arr));
}
快速排序(Quick Sort)
快速排序是对冒泡排序的一种改进
基本思想
-
通过一趟排序将要排序的数据分割为独立的两部分
-
一部分所有的数据都比另一部分所有的数据小
-
按上述方法对两部分数据进行快速排序
-
整个排序过程可以递归进行,达到整个数据编程有序序列
找一个基准,将数据序列分成两部分
代码实现
/**
* 快速排序
* @param arr
* @param left
* @param right
*/
public static void quickSort(int[] arr,int left,int right){
int l = left;//左下标
int r = right;//右下标
int pivot = arr[(left+right)/2];//基准数
int temp = 0;//临时变量
//左边索引大于等于右边索引时结束循环
//将比pivot小的数据放到左边,大的放到右边
while (l < r){
//在pivot左边找到大于或等于pivot的值,才退出
while (arr[l] < pivot){
l += 1;
}
//在pivot右边找到小于或等于pivot的值,才退出
while (arr[r] > pivot){
r -= 1;
}
//l >= r,pivot左右两边的值,已按照左边全部是小于等于pivot的值
//右边大于等于pivot的值
if (l >= r){
break;
}
//交换
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
//如果交换完后发现arr[l] == pivot,则r--,前移一步
if (arr[l] == pivot){
r -= 1;
}
//如果交换完后发现arr[r] == pivot,则l++,后移一步
if (arr[r] == pivot){
l += 1;
}
}
//如果l == r,必须l++,r--,否则会出现栈溢出
if (l == r){
l++;
r--;
}
//向左递归
if (left < r){
quickSort(arr,left,r);
}
//向右递归
if(right > l){
quickSort(arr,l,right);
}
}
归并排序(Merge Sort)
归并排序是利用归并的思想实现的排序方法,采用分治的策略。
基本思想
最后一次合并
代码实现
/**
* 归并排序
* @param arr
* @param left
* @param right
* @param temp
*/
public static void mergeSort(int[] arr,int left,int right,int[] temp){
if (left < right){
int mid = (left + right) / 2;
//向左递归进行分解
mergeSort(arr,left,mid,temp);
//向右递归进行分解
mergeSort(arr,mid+1,right,temp);
//到合并
merge(arr,left,mid,right,temp);
}
}
/**
* 归并排序合并的方法
* @param arr 待排序的数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 中转临时数组
*/
public static void merge(int[] arr,int left,int mid,int right,int[] temp){
//初始化i,j
int i = left; //左边序列的初始索引
int j = mid + 1; //右边有序序列的初始索引
int t = 0; //temp的索引
//(一)
//先把左右两边(有序)的数据按规则填充到temp数组
//直到左右两边有一边的有序序列处理完毕
while (i <= mid && j <= right){
//左边有序序列的当前元素小于或等于右边有序序列的当前元素
if (arr[i] <= arr[j]){
//将左边当前数据加入到temp中
// 并且将temp索引t和右边索引i,分别+=1
temp[t] = arr[i];
t += 1;
i += 1;
}else {//左边有序序列的当前元素大于右边有序序列的当前元素
//将右边当前数据加入到temp中
// 并且将temp索引t和右边索引j,分别+=1
temp[t] = arr[j];
t += 1;
j += 1;
}
}
//(二)
//把有剩余的一边的数据一次全部填充到temp
while (i <= mid){//左边还有剩余元素,全部填充到temp
temp[t] = arr[i];
t += 1;
i += 1;
}
while (j <= right){//右边还有剩余元素,全部填充到temp
temp[t] = arr[j];
t += 1;
j += 1;
}
//(三)