本文由网络资料整理而来,如有问题,欢迎指正!
// 排序原始数据
// 排序原始数据
private static final int[] NUMBERS =
{49, 38, 65, 97, 76, 13, 27, 78, 34, 12, 64, 5, 4, 62, 99, 98, 54, 56, 17, 18, 23, 34, 15, 35, 25, 53, 51};
插入排序 是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
基本思路: 取第 N 个元素( N 必须 >1)【假设 N 前面的元素,都已排好序了,一般从第2个元素开始比较】。
用 N 跟(N的下标-1)的元素比较,满足条件的,将(N的下标-1)元素向后移动一位。然后再将N 跟(N的下标-2)元素比较,满足条件的,将(N的下标-2)元素向后移动一位,以此类推,直到 不满足的时候,就停止比较。这里,假设比较(N的下标-5)元素的时候,不满足了。然后直接将 N 赋值给 (N的下标-4)的元素。
示例图:
JAVA代码:
public static void insertSort(int[] array) {
for (int i = 1; i < array.length; i++) {
int temp = array[i];//从下标为 1 的元素,即第二位数开始 比较
int j = i - 1;// 前一位下标,
for (; j >= 0 && array[j] > temp; j--) {
//将大于temp的值整体后移一个单位,
array[j + 1] = array[j];
//j-- 表示,将下一个比较对象向前移一个单位
}
//直到不满足条件,跳出内循环。
//此时的 j的值,就是那个不满足条件的比较对象的下标
//然后,将temp 插在它后面。
array[j + 1] = temp;
//最后 i++,继续下一轮外循环
}
System.out.println(Arrays.toString(array) + " insertSort");
}
希尔排序 也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位
基本思路: 基于上面说的两点性质,希尔排序,是将数据,从只能移动一位,改变成移动 N 位, 最后 N变成1,做最后一次 插入排序,然后 变成0,结束。
通俗的讲:就是在 做插入排序前,先做几次 粗略的 排序,以减少 插入排序的 移动次数。
因为 插入排序最大的弊端,就是每次只能移动一位,假设,要排序的数组是一段非常无序的,并且 每次循环都需要移动元素,那这就相当耗时,所以希尔排序的目的,是在执行最后的插入排序前,先用递增量,来对数组做几次粗略的排序,最后在将这个递增量变成1,已达到最后以插入排序做最后的排序,这样,就可以大大减少插入排序的循环次数和移动次数。
JAVA代码:
public static void shellSort(int[] array,int n) {
// array 是将要排序的数组
// n 为递增量
int i;
int j;
int temp;
int gap = 1;//默认值是1(如果是1,那就是 普通的 插入排序了),
int len = array.length;//数组长度
// len/n= 取整数倍 (13/5=2。 13%5=3)
while (gap < len / n) {
gap = gap * n + 1;//取 n 的整数倍 +1
//(+1,是为了保证,最后是以1为递增量,也就是插入排序)
}
//gap 为实际的运算递增量,随循环而变小,直至变为0,结束
/*
在插入排序中,递增量是1,效率低 ,
而希尔排序,就是通过增加递增量,
来提高 排序的效率
*/
for (; gap > 0; gap /= n) {
for (i = gap; i < len; i++) {
temp = array[i];
for (j = i - gap; j >= 0 && array[j] > temp; j -= gap) {
array[j + gap] = array[j];
}
array[j + gap] = temp;
}
}
System.out.println(Arrays.toString(array) + " shellSort");
}
简单选择排序 是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,因此对个元素的表进行排序总共进行至多次交换。在所有的完全依靠交换去移动元素的排序方法中,选择排序属于非常好的一种。
通俗讲:就是取数组第一位,依次跟后面所有的元素进行比较,一次完整的内循环后,满足条件的,交换位置。然后接着比第二位,一次类推,直到最后一位。
实例:
public static void selectSort(int[] array) {
int position = 0;// 满足条件的数据 所在位置
for (int i = 0; i < array.length; i++) {
int j = i + 1;
position = i;
int temp = array[i];// 被比较的数,从第i位开始,依次向后对比。
for (; j < array.length; j++) {
if (array[j] < temp) {
temp = array[j];// 获取最小数
position = j;//以及它的位置
}
}
array[position] = array[i];
array[i] = temp;
}
System.out.println(Arrays.toString(array) + " selectSort");
}
堆排序 是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。
基本思路:将要排序的数组 array,看着一颗完全二叉树结构。 array[0] 表示 根节点,array[length-1] 表示尾叶结点。
以数组索引,做二叉树的 编号。取 尾叶节点的 双亲节点, 即: 双亲的数组索引 = length/2-1 = (length-2)/2,依次向下做递归。
通俗讲:分为 三 步骤
- 先将要排序的数组堆化(即转成 满足完全二叉树特性的数组),并以 最大(或最小,根据需求) 数做根节点。
- 转完后,将根节点 和 最后的 尾结点交换,即(数组头尾元素交换)
- 然后将最后的元素,踢出下一轮的堆化。所谓的踢出,就是将第二轮的堆化,的数组长度参数减一,
依次类推,直到最后两个元素交换。
实例:
JAVA代码:
public static void heapSort(int[] array) {
/*
* 第一步:将数组堆化
* beginIndex = 第一个非叶子节点。
* 从第一个非叶子节点开始即可。无需从最后一个叶子节点开始。
* 叶子节点可以看作已符合堆要求的节点,根节点就是它自己且自己以下值为最大。
*/
int len = array.length - 1;
int beginIndex = (len - 1) >> 1;
for (int i = beginIndex; i >= 0; i--) {
maxHeapify(i, len, array);
}
/*
* 第二步:对堆化数据排序
* 每次都是移出最顶层的根节点A[0],与最尾部节点位置调换,同时遍历长度 - 1。
* 然后从新整理被换到根节点的末尾元素,使其符合堆的特性。
* 直至未排序的堆长度为 0。
*/
for (int i = len; i > 0; i--) {
swap(0, i, array);
maxHeapify(0, i - 1, array);
}
System.out.println(Arrays.toString(array) + " heapSort");
}
private static void swap(int i, int j, int[] arr) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
/**
* 调整索引为 index 处的数据,使其符合堆的特性。
*
* @param index 需要堆化处理的数据的索引
* @param len 未排序的堆(数组)的长度
*/
private static void maxHeapify(int index, int len, int[] arr) {
int li = (index << 1) + 1; // 左子节点索引
int ri = li + 1; // 右子节点索引
int cMax = li; // 子节点值最大索引,默认左子节点。
if (li > len) {
return; // 左子节点索引超出计算范围,直接返回。
}
if (ri <= len && arr[ri] > arr[li]) // 先判断左右子节点,哪个较大。
{ cMax = ri; }
if (arr[cMax] > arr[index]) {
swap(cMax, index, arr); // 如果父节点被子节点调换,
maxHeapify(cMax, len, arr); // 则需要继续判断换下后的父节点是否符合堆的特性。
}
}
冒泡排序 是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
基本思路: 内循环,完成 1 轮,能把 满足条件的 最大或最小,移动到数组最后。然后 i++,内循环,的长度就会length -1-i (即,不在操作,上一轮被移动到最后的那个元素。)直至 结束。
public static void bubbleSort(int[] array) {
int temp = 0;
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
System.out.println(Arrays.toString(array) + " bubbleSort");
}
快速排序 又称划分交换排序,简称快排,一种排序算法,最早由东尼·霍尔提出。在平均状况下,排序个项目要(大O符号)次比较。在最坏状况下则需要次比较,但这种状况并不常见。事实上,快速排序通常明显比其他算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地达成。
基本思路:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。
如何分成大小两部分的方法有很多,这里是将,基准元素 先后依次比较 数组尾首两端,向中间挤压。
通俗讲:就是找到元素,在数组中,本应该待的位置。 一般取第一或最后一个元素。 跟相反方向的元素,逐个比较(如果取的是第一个,就从数组尾巴开始向前比较,反之,则从数组开始向后比较)。当不满足条件,在跟其相反方向逐个比较,直到 被比较的元素的位置,不大于起始位置,不小于结束位置时,就是它的正确位置,并以此位置,将数组分成两部分,再以此相同的方法,找各个元素的正确位置。
package test.seowen;
import java.util.Arrays;
public class QuickSort {
public static void main(String[] args) {
int[] array = { 4, 3, 6, 2, 7, 1, 5, 4, 3, 6, 2, 7, 1, 54, 3, 6, 2, 7, 1, 5 };
QuickSort.qsort(array);
System.out.println(Arrays.toString(array) + " quickSort");
}
public static void qsort(int array[]) {
if (array != null && array.length > 0) {
_quickSort(array, 0, array.length - 1);
}
}
private static void _quickSort(int array[], int begin, int lastIndex) {
if (begin < lastIndex) {
int middle = _getMiddleSort(array, begin, lastIndex);// 将list数组进行一分为二
_quickSort(array, begin, middle - 1); // 对低字表进行递归排序
_quickSort(array, middle + 1, lastIndex);// 对高字表进行递归排序
}
}
private static int _getMiddleSort(int array[], int begin, int lastIndex) {
int temp = array[begin];// 基准数
while (begin < lastIndex) {
// 如果 末尾元素,大于 基准数,则末尾指针,向前移动一位。
while (begin < lastIndex && array[lastIndex] >= temp) {
lastIndex--;
}
// 否则,把末尾的这个数,赋值给 首部元素。
array[begin] = array[lastIndex];
// 然后 从首部元素,向后比较
while (begin < lastIndex && array[begin] <= temp) {
begin++;
}
// 否则,把末尾的这个数,赋值给 首部元素。
array[lastIndex] = array[begin];
}
array[begin] = temp;
System.out.println(begin);
return begin;
}
}
归并排序 是创建在归并操作上的一种有效的排序算法,效率为(大O符号)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。
基本思想:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
(2)实例:
JAVA 代码
public static void mergingSort(int[] array) {
sort(array, 0, array.length - 1);
System.out.println(Arrays.toString(array) + " mergingSort");
}
private static void sort(int[] data, int left, int right) {
if (left < right) {
//找出中间索引
int center = (left + right) / 2;
//对左边数组进行递归
sort(data, left, center);
//对右边数组进行递归
sort(data, center + 1, right);
//合并
merge(data, left, center, right);
}
}
private static void merge(int[] data, int left, int center, int right) {
int[] tmpArr = new int[data.length];
int mid = center + 1;
//third记录中间数组的索引
int third = left;
int tmp = left;
while (left <= center && mid <= right) {
//从两个数组中取出最小的放入中间数组
if (data[left] <= data[mid]) {
tmpArr[third++] = data[left++];
} else {
tmpArr[third++] = data[mid++];
}
}
//剩余部分依次放入中间数组
while (mid <= right) {
tmpArr[third++] = data[mid++];
}
while (left <= center) {
tmpArr[third++] = data[left++];
}
//将中间数组中的内容复制回原数组
while (tmp <= right) {
data[tmp] = tmpArr[tmp++];
}
}
基数排序 是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
public static void radixSort(int[] array) {
//首先确定排序的趟数;
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
int time = 0;
//判断位数;
while (max > 0) {
max /= 10;
time++;
}
//建立10个队列;
ArrayList<ArrayList<Integer>> queue = new ArrayList<>();
for (int i = 0; i < 10; i++) {
ArrayList<Integer> queue1 = new ArrayList<>();
queue.add(queue1);
}
//进行time次分配和收集;
for (int i = 0; i < time; i++) {
//分配数组元素;
for (int anArray : array) {
//得到数字的第time+1位数;
int x = anArray % (int)Math.pow(10, i + 1) / (int)Math.pow(10, i);
ArrayList<Integer> queue2 = queue.get(x);
queue2.add(anArray);
queue.set(x, queue2);
}
int count = 0;//元素计数器;
//收集队列元素;
for (int k = 0; k < 10; k++) {
while (queue.get(k).size() > 0) {
ArrayList<Integer> queue3 = queue.get(k);
array[count] = queue3.get(0);
queue3.remove(0);
count++;
}
}
}
System.out.println(Arrays.toString(array) + " radixSort");
}
---------------------
原文:https://blog.csdn.net/qy1387/article/details/7752973