代码为java实现,基于int[]。升序排序 。本文所使用的动态图是维基百科上获取的。
1. 插入排序算法
插入排序,会产生临时数组,空间复杂度与待排序数组元素个数成正比,时间复杂度与n平方成正比。
代码实现:先定义接口:
package org.util.sort;
/**
* 对int类型数组排序
* @author Weibing Long
* @since 2018.4.12
*/
public interface Sort {
void sort(int[] x);
}
然后定义插入排序:
package org.util.sort;
/**
* 插入排序,会产生临时数组,空间复杂度与待排序数组元素个数成正比,时间复杂度与n平方成正比。
* @author Weibing Long
* @since 2018.04.13
*/
public class InsertSort implements Sort {
public static void main(String args[]) {
Sort insertSort = new InsertSort();
int[] x = new int[] {
100, 40, 60, 87, 34, 11, 56, 0, 2, 57, 50, 40, 34
};
insertSort.sort(x);
for (int value : x) {
System.out.print(value + " ");
}
}
@Override
public void sort(int[] x) {
int[] y = new int[x.length];
y[0] = x[0];
for (int i = 1, j = 0; i < x.length; i++, j++) {
for (int k = 0; k < j + 1; k++) {
if (x[i] < y[k]) {
int temp = x[i];
x[i] = y[k];
y[k] = temp;
}
}
y[j + 1] = x[i];
}
for (int i = 0; i < x.length; i++) {
x[i] = y[i];
}
}
}
2. 希尔排序
稍微改善了插入排序,为啥叫希尔排序呢?
—- 我叫希尔,排序是我写的。有毛病吗?
算法实现:先定义接口:
package org.util.sort;
/**
* 对int类型数组排序
* @author Weibing Long
* @since 2018.4.12
*/
public interface Sort {
void sort(int[] x);
}
再实现接口:
package org.util.sort;
/**
* 希尔排序。(为啥叫希尔排序呢?---- 我叫希尔,排序是我写的。有毛病吗?)
* @author Weibing Long
* @since 2018.04.13
*/
public class ShellSort implements Sort {
public static void main(String[] args) {
Sort shellSort = new ShellSort();
int[] x = new int[] {
100, 40, 60, 87, 34, 11, 56, 0, 2, 57, 50, 40, 34
};
shellSort.sort(x);
for (int value : x) {
System.out.print(value + " ");
}
}
@Override
public void sort(int[] x) {
int stepSize = x.length / 3; // 步子大小
// 每一次循环就是一趟排序
while (stepSize >= 1) {
for (int i = 0; i < stepSize; i++) {
int n = 0;
// 计算待比较元素的个数,为了确定临时数组长度
for (int j = i; j < x.length; j = j + stepSize)
n++;
int[] temp = new int[n];
for (int j = i, k = 0; j < x.length; j = j + stepSize, k++) {
temp[k] = x[j];
}
// 对元素进行插入排序
Sort insertSort = new InsertSort();
insertSort.sort(temp);
for (int j = i, k = 0; j < x.length; j = j + stepSize, k++) {
x[j] = temp[k];
}
}
stepSize--; // 步子减一
}
}
}
3. 冒泡排序算法
第一趟遍历将数组中最大值放到最后。第二趟将第二大的数放到倒数第二的位置。。。。时间复杂度与n平方成正比。
代码实现:先定义接口:
package org.util.sort;
/**
* 对int类型数组排序
* @author Weibing Long
* @since 2018.4.12
*/
public interface Sort {
void sort(int[] x);
}
然后实现接口:
package org.util.sort;
/**
* 冒泡排序:时间复杂度与n平方成正比
* @author Weibing Long
* @since 2018.04.13
*/
public class BubbleSort implements Sort {
public static void main(String[] args) {
Sort bubbleSort = new BubbleSort();
int[] x = new int[] {
100, 40, 60, 87, 34, 11, 56, 0, 2, 57, 50, 40, 34
};
bubbleSort.sort(x);
for (int value : x) {
System.out.print(value + " ");
}
}
@Override
public void sort(int[] x) {
for (int i = 0; i < x.length; i++) {
for (int j = i + 1; j < x.length; j++) {
if (x[i] > x[j]) {
swap(x, i, j);
}
}
}
}
// 交换元素
private void swap(int[] x, int i, int j) {
int temp = x[i];
x[i] = x[j];
x[j] = temp;
}
}
4. 快速排序算法
快速排序。它是一种基于交换排序的排序算法,目前公认最好的排序算法。发明者是C. A. R. Hoare
算法思想:第一个元素作为基准,将大于它的元素排在右边,小于它的元素排在左边。然后用同样的方式对左右两边的数据进行整理,直到只剩两个元素的比较为止。比较两个元素,将小的排在左边。该算法涉及到分治思想和递归思想。
算法实现:代码为Java,首先设计了一个排序接口,
package org.util.sort;
/**
* 对int类型数组排序
* @author Weibing Long
* @since 2018.4.12
*/
public interface Sort {
void sort(int[] x);
}
然后实现快速排序
/**
* 快速排序。它是一种基于交换排序的排序算法,目前公认最好的排序算法。发明者是C. A. R. Hoare<hr>
* 算法思想:第一个元素作为基准,将大于它的元素排在右边,小于它的元素
* 排在左边。然后用同样的方式对左右两边的数据进行整理,直到只剩两个元素的比较为止。
* 比较两个元素,将小的排在左边。<br>
*
* 该算法涉及到分治思想和递归思想。
* @author Weibing Long
*
*/
public class QuickSort implements Sort {
public static void main(String[] args) {
QuickSort quickSort = new QuickSort();
int[] x = new int[] {
100, 40, 60, 87, 34, 11, 56, 0,2, 57, 50,40,34
};
quickSort.sort(x);
for (int i = 0; i < x.length; i++) {
System.out.print(x[i] + " ");
}
}
@Override
public void sort(int[] x) {
sort(x, 0, x.length - 1);
}
private void sort(int[] x, int low, int high) {
if (low >= high)
return;
// x在low和high指定的范围元素仅两个
if (high - low == 1) {
if (x[low] > x[high])
swap(x, low, high);
return;
}
int pivot = x[low]; // 基准元素
int left = low + 1;
int right = high;
while (left < right) {
while (left < right && left <= high) {
if (x[left] > pivot)
break;
left++;
}
while (left <= right && right > low) {
if (x[right] < pivot)
break;
right--;
}
if (left < right)
swap(x, left, right);
}
swap(x, low, right);
sort(x, low, right - 1);
sort(x, right + 1, high);
}
// 交换数组在left和right处两个元素的值
private void swap(int[] x, int left, int right) {
int temp = x[left];
x[left] = x[right];
x[right] = temp;
}
}
实验中对于 ‘left <= right && right > low’ 条件,我忘记写等号导致出错。
对于递归调用的函数,在函数开头一定要写入口检查,这是终止递归调用的关键。
实验结果:0 2 11 34 34 40 40 50 56 57 60 87 100
5. 选择排序
选择排序:一趟遍历将最小的数记录下来,然后与第一个元素交换位置。
(注意与冒泡排序的区别,最坏情况下,虽然时间复杂度一样N平方,但是选择排序更有效)
先定义接口:
package org.util.sort;
/**
* 对int类型数组排序
* @author Weibing Long
* @since 2018.4.12
*/
public interface Sort {
void sort(int[] x);
}
然后实现接口:
package org.util.sort;
/**
* 选择排序:一趟遍历将最小的数记录下来,然后与第一个元素交换位置。
* (注意与冒泡排序的区别,最坏情况下,虽然时间复杂度一样N平方,但是选择排序更有效)
* 这里理解如有错误,欢迎指正!
* @author Weibing Long
* @since 2018.04.14
*/
public class SelectSort implements Sort {
public static void main(String[] args) {
Sort selectSort = new SelectSort();
int[] x = new int[] {
100, 40, 60, 87, 34, 11, 56, 0, 2, 57, 50, 40, 34
};
selectSort.sort(x);
for (int value : x) {
System.out.print(value + " ");
}
}
@Override
public void sort(int[] x) {
for (int i = 0; i < x.length; i++) {
int min = i;
for (int j = i + 1; j < x.length; j++) {
if (x[j] < x[min]) {
min = j;
}
}
if (min != i)
swap(x, min, i);
}
}
private void swap(int[] x, int i, int j) {
int temp = x[i];
x[i] = x[j];
x[j] = temp;
}
}
6. 堆排序算法
- 堆排序,基于选择排序(基本操作是选择,或者理解为时间主要花费在选择操作)。
- 对于给定的int类型数组,首先将它组织为最大堆(堆是一种数据结构,数据结构就是数据的组织方式。最大堆满足:是一个完全二叉树,而且父节点比直接左右子树节点值大。)然后将最后一个元素与第一个元素交换。这是一次迭代。
- 第二次的时候,组织最大堆的时候,不包括最后一个元素,因为它的位置已经确定了。第二次迭代再将第一个元素与倒数第二个元素交换位置。
- 以此类推。
算法实现:先定义接口:
package org.util.sort;
/**
* 对int类型数组排序
* @author Weibing Long
* @since 2018.4.12
*/
public interface Sort {
void sort(int[] x);
}
然后实现接口:
package org.util.sort;
/**
* 堆排序,基于选择排序(基本操作是选择,或者理解为时间主要花费在选择操作)。
* 对于给定的int类型数组,首先将它组织为最大堆(堆是一种数据结构,数据结构就是数据的组织方式。最大堆满足:是一个完全二叉树,而且父节点比直接左右子树节点值大。)
* 然后将最后一个元素与第一个元素交换。这是一次迭代。第二次的时候,组织最大堆的时候,不包括最后一个元素,因为它的位置已经确定了。
* 第二次迭代再将第一个元素与倒数第二个元素交换位置,以此类推。
* @author Weibing Long
* @since 2018.04.15
*/
public class HeapSort implements Sort {
public static void main(String[] args) {
Sort heapSort = new HeapSort();
int[] x = new int[] {
100, 40, 60, 87, 34, 11, 56, 0, 2, 57, 50, 40, 34
};
heapSort.sort(x);
for (int value : x) {
System.out.print(value + " ");
}
}
@Override
public void sort(int[] x) {
// 从后往前,将最大的值依次赋值
for (int i = x.length - 1, j = 0; i > 0; i--, j++) {
// 建大顶堆
int y = 0;
// 当前节点左右子树都存在
while (2 * y + 2 < x.length - j) {
int maxIndex = y;
if (x[maxIndex] < x[2 * y + 1])
maxIndex = 2 * y + 1;
if (x[maxIndex] < x[2 * y + 2])
maxIndex = 2 * y + 2;
// 使父节点最大
if (maxIndex != y) {
swap(x, maxIndex, y);
backtrace(x, y);
}
y++;
}
// 当前节点存在左子树,不存在右子树,而且做子树节点值更大。
if (2 * y + 1 < x.length - j && x[y] < x[2 * y + 1]) {
swap(x, 2 * y + 1, y);
backtrace(x, y);
}
//交换元素
swap(x, i, 0);
}
}
// 交换元素
private void swap(int[] x, int i, int j) {
int temp = x[i];
x[i] = x[j];
x[j] = temp;
}
// 回溯操作,主要是从当前索引curindex开始,将较大的值从父节点一直传送到根节点。
private void backtrace(int[] x, int curindex) {
int i1 = curindex;
int i2 = (i1 - 1) / 2;
while (i2 >= 0 && x[i1] > x[i2]) {
swap(x, i1, i2);
i1 = i2;
i2 = (i1 - 1) / 2;
if (i1 == 0) break;
}
}
}
7. 归并排序算法
- 归并排序:此算法与快速排序有些类似,运行效率也很好,但是需要额外的空间。
- 此外,归并对半后,分别排序,然后合并数组。而快速排序对半的依据是某个元素。
代码实现:先定义接口:
package org.util.sort;
/**
* 对int类型数组排序
* @author Weibing Long
* @since 2018.4.12
*/
public interface Sort {
void sort(int[] x);
}
然后实现接口:
package org.util.sort;
/**
* 归并排序:此算法与快速排序有些类似,运行效率也很好,但是需要额外的空间。
* 此外,归并对半后,分别排序,然后合并数组。而快速排序对半的依据是某个元素。
* @author Weibing Long
* @since 2018.04.15
*/
public class MergeSort implements Sort {
public static void main(String[] args) {
Sort mergetSort = new MergeSort();
int[] x = new int[] {
100, 40, 60, 87, 34, 11, 56, 0, 2, 57, 50, 40, 34
};
mergetSort.sort(x);
for (int value : x) {
System.out.print(value + " ");
}
}
@Override
public void sort(int[] x) {
sort(x, 0, x.length - 1);
}
private void sort(int[] x, int low, int high) {
if (high - low == 0)
return;
if (high - low == 1) {
if (x[low] > x[high])
swap(x, low, high);
return;
}
long sum = low + high;
int middle = (int)(sum / 2);
sort(x, low, middle);
sort(x, middle + 1, high);
merge(x, low, high);
}
private void merge(int[] x, int low, int high) {
int n = high - low + 1;
int[] temp = new int[n];
long sum = low + high;
int mid = (int)(sum / 2), left = low, right = mid + 1, i = 0;
while (left <= mid && right <= high) {
if (x[left] <= x[right]) temp[i++] = x[left++];
else temp[i++] = x[right++];
}
if (left > mid)
while (right <= high) temp[i++] = x[right++];
if (right > high)
while (left <= mid) temp[i++] = x[left++];
int index = 0;
for (i = low; i <= high; i++, index++)
x[i] = temp[index];
}
private void swap(int[] x, int i, int j) {
int temp = x[i];
x[i] = x[j];
x[j] = temp;
}
}
8. 基数排序算法
- 基数排序:基于桶排序,从个位、十位、百位。。。。。。迭代,每次迭代的时候,如果某位是5,就存入对应的0到9中的编号为5的桶中,然后依次重新放入原数组中。终止条件为所有的数都存入编号为0的桶中,即都超过了最高位。
- 实现细节:针对可能存在负数,所以先找出原数组中最小的数,然后将所有的数都加上该数的绝对值后再求对应位的数,这样保证了负数为自然数,而且它们与正数的相对关系不发生变化。
- 具体代码体现在这里:((x[i] + Math.abs(minvalue)) / offset) % 10
代码实现:先定义接口:
package org.util.sort;
/**
* 对int类型数组排序
* @author Weibing Long
* @since 2018.4.12
*/
public interface Sort {
void sort(int[] x);
}
然后实现接口:
package org.util.sort;
import java.util.*;
/**
* 基数排序:基于桶排序,从个位、十位、百位。。。。。。迭代,每次迭代的时候,
* 如果某位是5,就存入对应的0到9中的编号为5的桶中,然后依次重新放入原数组中。终止条件为所有的数
* 都超过了最高位。
* 实现细节:针对可能存在负数,所以先找出原数组中最小的数,然后将所有的数都加上该数的绝对值后
* 再求对应位的数,这样保证了负数为自然数,而且它们与正数的相对关系不发生变化。具体代码体现在
* 这里:((x[i] + Math.abs(minvalue)) / offset) % 10
* @author Weibing Long
* @since 2018.04.16
*/
public class RadixSort implements Sort {
// 创建从0到9的十个桶
private static final Map<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
static {
for (int i = 0; i < 10; i++)
map.put(i, new ArrayList<Integer>());
}
public static void main(String[] args) {
Sort radixSort = new RadixSort();
int[] x = new int[] {
100, 40, 60, 87, 34, 11, 56, 0, 2, 57, 50, 40, 34
};
radixSort.sort(x);
for (int i = 0; i < x.length; i++) {
System.out.print(x[i] + " ");
}
}
@Override
public void sort(int[] x) {
sort(x, 1);
}
private void sort(int[] x, long offset) {
int minvalue = min(x);
// 填桶
for (int i = 0; i < x.length; i++) {
// (x[i] + Math.abs(minvalue)) 保证所有的数都为正数,而且相对大小不变
long sum = (((long)x[i] + (long)Math.abs(minvalue)) / offset); // 防止溢出
map.get((int)(sum % 10)).add(i);
}
offset *= 10;
// 终止条件
long max = ((long)Math.abs(minvalue) + max(x)) * 10;
if (max < offset)
return;
else {
int[] temp = new int[x.length];
int m = 0;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < map.get(i).size(); j++) {
temp[m++] = x[map.get(i).get(j)];
}
}
for (int i = 0; i < x.length; i++) {
x[i] = temp[i];
}
for (int i = 0; i < map.size(); i++) {
map.get(i).clear();
}
sort(x, offset);
}
}
// 求数组中最小的数
private int min(int[] x) {
int min = Integer.MAX_VALUE;
for (int value : x) {
if (min > value)
min = value;
}
return min;
}
// 求数组中最小的数
private int max(int[] x) {
int max = Integer.MIN_VALUE;
for (int value : x) {
if (max < value)
max = value;
}
return max;
}
}
谨防溢出
jar包下载地址是:https://download.csdn.net/download/github_37412255/10510801