目录
1. 排序算法分类
2. 不稳定排序
2.1 插入排序
/**
* 选择排序
* 每一次从待排序的数据元素中选出最小(或最大)的一个元素,
* 存放在序列的起始位置,直到全部待排序的数据元素排完。
* 时间复杂度:O(n^2)
* 空间复杂度:O(1)
* @param arr
*/
public void selectSort(int arr[]) {
for(int i = arr.length-1; i >= 0; i--) {
int tmp = arr[i];
int index = i;
for(int j = 0; j < i; j++) {
if(arr[j] > tmp) {
index = j;
tmp = arr[j];
}
}
arr[index] = arr[i];
arr[i] = tmp;
}
}
2.2 快速排序
/**
* 快速排序:
* 通过一趟排序将要排序的数据分割成独立的两部分,
* 其中一部分的所有数据都比另外一部分的所有数据都要小,
* 然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,
* 以此达到整个数据变成有序序列。
*
* 1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
* 2)以第一个数组元素作为关键数据,赋值给key,即key=A[0]
* 3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换
* 4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换
* 5)重复第3、4步,直到i=j;
* (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值
* 使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。
* 另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
*
* 时间复杂度:
* 最好O(nlogn)
* 最坏:O(n^2)
* 空间复杂度:O(nlogn)
*
* @param arr
*/
public void fastSort(int arr[], int begin, int end){
if(begin >= end) {
return;
}
int index = partition(arr, begin, end);
fastSort(arr, begin, index-1);
fastSort(arr, index+1, end);
}
private int partition(int arr[], int begin, int end) {
int tmp = arr[begin];
while(begin < end) {
while(begin < end && arr[end] >= tmp) {
end--;
}
arr[begin] = arr[end];
while(begin < end && arr[begin] <= tmp) {
begin++;
}
arr[end] = arr[begin];
}
arr[end] = tmp;
return begin;
}
2.3 堆排序 - 完全二叉树
/**
* 堆排序
* 将二叉树调整为大顶堆,然后将堆的最后一个元素与堆顶元素(即二叉树的根结点)进行交换后,
* 堆的最后一个元素即为最大记录;接着将前n-1个元素调整为大顶堆,
* 再将堆顶元素与当前堆的最后一个元素进行交换后得到次大的记录
* 重复该过程直到调整的堆中只剩一个元素为止,该元素即为最小记录,
* 此时可得到一个有序序列
*
* 时间复杂度:O(nlogn)
* 空间复杂度:O(1)
*
* @param arr
*/
public void heapSort(int arr[]) {
for(int i = arr.length/2-1; i >=0; i--) {
headAdjust(arr, i, arr.length-1);
}
for(int j = arr.length-1; j >= 0; j--) {
swap(arr, j, 0);
for(int i = j/2-1; i >=0; i--) {
headAdjust(arr, i, j-1);
}
}
}
private void headAdjust(int arr[], int index,int len) {
for(int i = index*2+1; i <= len && i<=index*2+2; i++) {
if(arr[i] > arr[index]) {
swap(arr, i, index);
}
}
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
3. 稳定排序
3.1 冒泡排序
/**
* 冒泡排序:
* 1. 比较相邻的元素。如果第一个比第二个大,将两个值进行交换。
* 2. 对每一对相邻的元素做同样的工作,从开始到第一对到最后一对。
* 比较结果是最大的元素在最后一位。
* 3. 针对所有的元素重复以上的步骤,除了最后一个。
* 针对每次越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
*
* 最好时间复杂度:O(n)
* 最坏时间复杂度:O(n^2)
*
* 平均时间复杂度:O(n^2)
* 空间复杂度:O(1)
*
* @param arr 待排序数组
*/
public void bubbleSort(int arr[]) {
boolean flag = true; // 记录数组是否已经有序,默认true:无序,false:有序
for(int i = arr.length-1; i >= 0 && flag; i--) {
flag = false;
for(int j = 0; j < i; j++) {
if(arr[j] > arr[j+1]) {// 数据无序时,进行交换
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
flag = true; // 当本次循环有数据交换,代表当前无序
}
}
}
}
3.2 直接插入排序
/**
* 直接插入排序:
* 1. 首先在当前有序区R[1..i-1]中查找R[i]的正确插入位置k(1≤k≤i-1);
* 2. 然后将R[k..i-1]中的记录均后移一个位置,腾出k位置上的空间插入R[i]。
*
* 时间复杂度:O(n^2)
* 空间复杂度:O(1)
*
* @param arr 待排序数组
*/
public void insertSort(int[] arr) {
if(arr == null || arr.length <= 1) { // 当数组为空,或者数组长度小于等于1时,不需要排序
return;
}
for(int i = 1; i < arr.length; i++) {
int tmp = arr[i];
int j;
for(j = i; j > 0 && arr[j-1] > tmp; j--) {
arr[j] = arr[j-1];
}
arr[j] = tmp;
}
}
3.3 归并排序
/**
* 归并排序:
* 将每两个相邻的长度为1的子序列进行归并,得到n/2个长度为2或1的有序子数列,
* 再将两两归并,反复执行此过程,直到得到一个有序序列
*
* 时间复杂度:O(nlogn)
* 空间复杂度:O(n)
*
* @param arr 待排序数组
* @param begin 开始位置
* @param end 结束位置
*/
public void mergeSort(int arr[], int begin, int end) {
int mid = (begin + end)/2;
if(begin < end) {
mergeSort(arr, begin, mid);
mergeSort(arr, mid+1, end);
merge(arr, begin, mid, end);
}
}
private void merge(int arr[], int begin, int mid, int end) {
int[] tmp = new int[end-begin+1];
int i = begin;
int j = mid + 1;
int k = 0;
while(i <= mid && j <= end) {
if(arr[i] < arr[j]) {
tmp[k++] = arr[i++];
}else {
tmp[k++] = arr[j++];
}
}
while(i <= mid) {
tmp[k++] = arr[i++];
}
while(j <= end) {
tmp[k++] = arr[j++];
}
for(int t = 0; t < tmp.length; t++) {
arr[begin+t] = tmp[t];
}
}
4. 运行结果比较
5. 总结
算法是代码的灵魂,而算法的实现只是基础,在此基础上面还要进行算法优化,本次只是算法的实现,算是对排序的复习,并没有进行优化操作。
就像上面的运行结果一样,同等条件下,对各个排序算法各自随机产生一个长度为5000的整型数组,只不过对冒泡进行了一点优化,结果可以看出此时冒泡的性能竟然是最好的,比快速排序还要快两个数量级。
这就是优化的力量,通过优化可以让算法速度有大幅度的提升,才是进步的方向。