标签:
这里总的给出了几种常用的排序算法,也是当作复习和巩固.
以上几个都是根据排序的原理和原则自定义实现的.对于同一个排序实际的实现过程可能有一些不同,但思想和处理方式是相同的.
//插入排序
public static boolean insertSort(int[] src, boolean isAsc) {
if (src != null) {
return insertSort(src, 0, src.length - 1, isAsc);
} else {
return false;
}
}
//指定数组的某一段进行排序
//startIndex/endIndex分别为数组中开始排序的位置
private static boolean insertSort(int[] src, int startIndex, int endIndex, boolean isAsc) {
if (src == null || startIndex > endIndex) {
return false;
} else {
int temp = 0;
for (int i = startIndex; i <= endIndex; i++) {
//取下一个位置的数据
for (int k = 0; k < i; k++) {
swap(src, k, i, isAsc);
}
}
return true;
}
}
//希尔排序是基于插入排序的,先将数组分为N份进行插入排序,完成后减小增量再进行排序
public static boolean shellSort(int[] src, boolean isAsc) {
if (src == null) {
return false;
} else {
//计算一个增量
int increment = src.length / 4;
if (increment <= 0) {
//增量必须大于等于1
increment = 1;
}
//增量递减进行排序
for (int i = increment; i >= 1; i--) {
int j = 0;
//增量分组进行插入排序
for (; j + i < src.length; j += i) {
insertSort(src, j, j + i, isAsc);
}
//如果数组不能完全按增量切分,最后部分也可以正常排序
insertSort(src, j, src.length - 1, isAsc);
}
return true;
}
}
//依次从数组中每次取出最值,按序排放直到排序结束
public static boolean simpleSort(int src[], boolean isAsc) {
if (src == null) {
return false;
} else {
for (int i = 0; i < src.length; i++) {
//记录第N个要排序的位置
int j = i;
//记录当前最大/小值的位置
int k = j;
for (; j + 1 < src.length; j++) {
if (isAsc) {
if (src[k] > src[j + 1]) {
//若当前值小于记录值,更新记录值的位置,否则记录值位置不变
k = j + 1;
}
} else {
if (src[k] > src[j + 1]) {
k = j + 1;
}
}
}
j = src[i];
src[i] = src[k];
src[k] = j;
}
return true;
}
}
//堆排序
public static boolean heapSort(int[] src, boolean isAsc) {
if (src == null) {
return false;
} else {
//这里的处理方法是:
//将数组进行堆排序,得到第一个值为最大/小值;
//除去第一个值,对后面的数组再次堆排序,得到第二个值为二次数组的最大/小值,即该值为数组中的第二大/小值
//重复以上的方法直到数组被完全排序
for (int i = 0; i < src.length; i++) {
//依次建堆,得到一个堆后就排除1项重新建堆
buildHeap(src, i, src.length - 1, !isAsc);
}
return true;
}
}
//建堆,将数组指定的索引范围内的数据进行建堆
private static void buildHeap(int[] src, int startIndex, int endIndex, boolean isBiggest) {
if (src == null || startIndex > endIndex) {
return;
} else {
//计算出当前排序的数组长度
int length = endIndex - startIndex;
//得到当前计算数组的中间位置
int mid = (length - 1) / 2;
for (int i = mid; i >= 0; i--) {
//计算中间位置的左子树位置
int left = i * 2 + 1 + startIndex;
//计算中间位置的右子树位置
int right = left + 1;
//若左子树位置有效,则尝试比较左子树及其父节点并交换
if (left <= endIndex) {
swap(src, left, i + startIndex, isBiggest);
}
//若右子树位置有效,尝试比较右子树及其父节点并交换
if (right <= endIndex) {
swap(src, right, i + startIndex, isBiggest);
}
}
}
}
这里的堆排序与定义上的排序是有一些不同的.定义上的堆排序是建成堆后,最后一个数据与堆顶交换;这里是建堆后取走第一个最值,其它的数据直接重新建成一个堆,重复直到堆中只有一个数据为止.(不存在堆顶数据与最后的数据进行交换)
public static boolean bubbleSort(int[] src, boolean isAsc) {
if (src == null) {
return false;
} else {
boolean isFinish = false;
while (!isFinish) {
isFinish = true;
for (int i = 0; i + 1 < src.length; i++) {
if (swap(src, i, i + 1, isAsc)) {
//只要进行过交换,就说明还没有排序完成,直到不再交换为止
isFinish = false;
}
}
}
return true;
}
}
public static boolean quickSort(int[] src, boolean isAsc) {
if (src == null) {
return false;
} else {
//一趟扫描的递归操作
onceRecursionSort(src, 0, src.length - 1, isAsc);
return true;
}
}
快速排序是基于一趟扫描的;一趟扫描是选择一个数值划分出数组的大小区域,每个区域再重复这个过程直到所有区域不再需要划分为止.
一趟快速排序的算法是:
//一趟快速扫描
private static void onceRecursionSort(int[] src, int left, int right, boolean isAsc) {
if (src == null || left > right) {
return;
} else {
//保存初始值
int stickLeft = left;
int stickRight = right;
//选择排序标准值
int key = src[stickLeft];
//进行一次大小值区分的排序
while (left < right) {
//从右边开始向左边扫描
while (left < right) {
//当前左右两个数值是否满足比较条件(此处为左<右)
if (!isCompareCorrect(src[right], key, isAsc)) {
//右边数大于标准值时,检测索引左移
right--;
continue;
}
//否则交换数据,并且左边索引右移(因为左边已经与右边交换了,不再需要检测左边的值)
swap(src, left, right);
left++;
break;
}
//从左边开始向右边扫描
while (left < right) {
if (!isCompareCorrect(key, src[left], isAsc)) {
left++;
continue;
}
swap(src, left, right);
right--;
break;
}
}
//当中间值小于初始值时,说明没有完全排序完整,递归进行排序,重复每个区域的排序
if (stickLeft < right) {
onceRecursionSort(src, stickLeft, right, isAsc);
}
if (right + 1 < stickRight) {
onceRecursionSort(src, right + 1, stickRight, isAsc);
}
}
}
public class SortAlgorithm {
/**
* 插入排序<br/>
* 基本思想:在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。
*
* @param src
*/
public static boolean insertSort(int[] src, boolean isAsc) {
if (src != null) {
return insertSort(src, 0, src.length - 1, isAsc);
} else {
return false;
}
}
/**
* 指定数组的某一段进行排序
*
* @param src
* @param startIndex 开始排序的index
* @param endIndex 结束排序的index
* @param isAsc 是否升序
*/
private static boolean insertSort(int[] src, int startIndex, int endIndex, boolean isAsc) {
if (src == null || startIndex > endIndex) {
return false;
} else {
int temp = 0;
for (int i = startIndex; i <= endIndex; i++) {
//取下一个位置的数据
for (int k = 0; k < i; k++) {
swap(src, k, i, isAsc);
}
}
return true;
}
}
/**
* 希尔排序<br/>
* 基本思想:算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成。
*
* @param src
* @param isAsc 是否升序
* @return
*/
public static boolean shellSort(int[] src, boolean isAsc) {
if (src == null) {
return false;
} else {
//计算一个增量
int increment = src.length / 4;
if (increment <= 0) {
//增量必须大于等于1
increment = 1;
}
//增量递减进行排序
for (int i = increment; i >= 1; i--) {
int j = 0;
//增量分组进行插入排序
for (; j + i < src.length; j += i) {
insertSort(src, j, j + i, isAsc);
}
//如果数组不能完全按增量切分,最后部分也可以正常排序
insertSort(src, j, src.length - 1, isAsc);
}
return true;
}
}
/**
* 简单排序<br/>
* 基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。
*
* @param src
* @param isAsc 是否升序
* @return
*/
public static boolean simpleSort(int src[], boolean isAsc) {
if (src == null) {
return false;
} else {
for (int i = 0; i < src.length; i++) {
//记录第N个要排序的位置
int j = i;
//记录当前最大/小值的位置
int k = j;
for (; j + 1 < src.length; j++) {
if (isAsc) {
if (src[k] > src[j + 1]) {
//若当前值小于记录值,更新记录值的位置,否则记录值位置不变
k = j + 1;
}
} else {
if (src[k] > src[j + 1]) {
k = j + 1;
}
}
}
j = src[i];
src[i] = src[k];
src[k] = j;
}
return true;
}
}
/**
* 堆排序<br/>
* 基本思想:堆排序是一种树形选择排序,是对直接选择排序的有效改进。<br/>
* 堆的定义如下:具有n个元素的序列(h1,h2,…,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1) (i=1,2,…,n/2)时称之为堆。在这里只讨论满足前者条件的堆。由堆的定义可以看出,堆顶元素(即第一个元素)必为最大项(大顶堆)。完全二叉树可以很直观地表示堆的结构。堆顶为根,其它为左子树、右子树。初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。
*
* @param src
* @param isAsc 是否升序
* @return
*/
public static boolean heapSort(int[] src, boolean isAsc) {
if (src == null) {
return false;
} else {
//这里的处理方法是:
//将数组进行堆排序,得到第一个值为最大/小值;
//除去第一个值,对后面的数组再次堆排序,得到第二个值为二次数组的最大/小值,即该值为数组中的第二大/小值
//重复以上的方法直到数组被完全排序
for (int i = 0; i < src.length; i++) {
//依次建堆,得到一个堆后就排除1项重新建堆
buildHeap(src, i, src.length - 1, !isAsc);
}
return true;
}
}
/**
* 冒泡排序<br/>
* 基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。
*
* @param src
* @param isAsc
* @return
*/
public static boolean bubbleSort(int[] src, boolean isAsc) {
if (src == null) {
return false;
} else {
boolean isFinish = false;
while (!isFinish) {
isFinish = true;
for (int i = 0; i + 1 < src.length; i++) {
if (swap(src, i, i + 1, isAsc)) {
//只要进行过交换,就说明还没有排序完成,直到不再交换为止
isFinish = false;
}
}
}
return true;
}
}
/**
* 快速排序<br/>
* 基本思想:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。
*
* @param src
* @param isAsc
* @return
*/
public static boolean quickSort(int[] src, boolean isAsc) {
if (src == null) {
return false;
} else {
//一趟扫描的递归操作
onceRecursionSort(src, 0, src.length - 1, isAsc);
return true;
}
}
/**
* 递归的一趟扫描<br/>
* 一趟快速排序的算法是:<br/>
* 1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;<br/>
* 2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];<br/>
* 3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;<br/>
* 4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;<br/>
* 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-完成的时候,此时令循环结束)。<br/>
*
* @param src
* @param left
* @param right
* @param isAsc
*/
private static void onceRecursionSort(int[] src, int left, int right, boolean isAsc) {
if (src == null || left > right) {
return;
} else {
//保存初始值
int stickLeft = left;
int stickRight = right;
//选择排序标准值
int key = src[stickLeft];
while (left < right) {
//从右边开始向左边扫描
while (left < right) {
//当前左右两个数值是否满足比较条件(此处为左<右)
if (!isCompareCorrect(src[right], key, isAsc)) {
//右边数大于标准值时,检测索引左移
right--;
continue;
}
//否则交换数据,并且左边索引右移(因为左边已经与右边交换了,不再需要检测左边的值)
swap(src, left, right);
left++;
break;
}
//从左边开始向右边扫描
while (left < right) {
if (!isCompareCorrect(key, src[left], isAsc)) {
left++;
continue;
}
swap(src, left, right);
right--;
break;
}
}
//当中间值小于初始值时,说明没有完全排序完整,递归进行排序
if (stickLeft < right) {
onceRecursionSort(src, stickLeft, right, isAsc);
}
if (right + 1 < stickRight) {
onceRecursionSort(src, right + 1, stickRight, isAsc);
}
}
}
/**
* 数组中从指定位置startIndex到endIndex建堆进行排序
* 结过排序后src[startIndex]位置的值为堆中最大/小值(其它位置的值并不确定)
*
* @param src
* @param startIndex 开始位置索引
* @param endIndex 结束位置索引
* @param isBiggest 是否大顶堆
*/
private static void buildHeap(int[] src, int startIndex, int endIndex, boolean isBiggest) {
if (src == null || startIndex > endIndex) {
return;
} else {
//计算出当前排序的数组长度
int length = endIndex - startIndex;
//得到当前计算数组的中间位置
int mid = (length - 1) / 2;
for (int i = mid; i >= 0; i--) {
//计算中间位置的左子树位置
int left = i * 2 + 1 + startIndex;
//计算中间位置的右子树位置
int right = left + 1;
//若左子树位置有效,则尝试比较左子树及其父节点并交换
if (left <= endIndex) {
swap(src, left, i + startIndex, isBiggest);
}
//若右子树位置有效,尝试比较右子树及其父节点并交换
if (right <= endIndex) {
swap(src, right, i + startIndex, isBiggest);
}
}
}
}
/**
* 在满足要求时交换指定位置的两个索引的值
*
* @param src
* @param firstIndex
* @param secondIndex
* @param isFirstBiggerThanSecond 第一个数是否大于第二个数,当此参数为true时,若scr[firstIndex]>src[secondIndex],交换值,否则不操作返回false
* @return
*/
private static boolean swap(int[] src, int firstIndex, int secondIndex, boolean isFirstBiggerThanSecond) {
int temp = 0;
boolean isChanged = false;
if (isFirstBiggerThanSecond && src[firstIndex] > src[secondIndex]) {
isChanged = true;
} else if (!isFirstBiggerThanSecond && src[firstIndex] < src[secondIndex]) {
isChanged = true;
}
if (isChanged) {
temp = src[firstIndex];
src[firstIndex] = src[secondIndex];
src[secondIndex] = temp;
}
return isChanged;
}
/**
* 交换指定位置的两个数值
*
* @param src
* @param firstIndex
* @param secondIndex
*/
public static void swap(int[] src, int firstIndex, int secondIndex) {
int temp = 0;
temp = src[firstIndex];
src[firstIndex] = src[secondIndex];
src[secondIndex] = temp;w
}
/**
* 判断当前两个值的比较是否按要求正常
*
* @param firstInt
* @param secondInt
* @param isAsc 是否按升序排序,当此参数为true时,若第一个数<第二个数,返回true,否则返回false
* @return
*/
private static boolean isCompareCorrect(int firstInt, int secondInt, boolean isAsc) {
if (isAsc) {
return firstInt < secondInt;
} else {
return firstInt > secondInt;
}
}
}
标签:
原文地址:http://blog.csdn.net/u011374875/article/details/51896407