最近整理了一下各种排序算法,代码如下,欢迎大家提问与转载,转载请注明出处
import java.util.Arrays;
public class ArraySort {
//插入排序:直接插入排序
public void insertSort(int [] array) {
if(array.length == 0 || array.length == 1) return;
for(int i = 1;i < array.length;i ++) {
//从后往前遍历
int temp = array[i];
int j = i - 1;
for(;j >= 0 && array[j] > temp;j --) {
array[j + 1] = array[j]; //比temp大的数整体后移
}
array[j + 1] = temp;
}
}
public void insertSort2(int [] array) {
if(array.length == 0 || array.length == 1) return;
for(int i = 1;i < array.length;i ++) {
//从后往前遍历
int index = i;
for(int j = i - 1;j >= 0 && array[j] > array[index];j --) {
int temp = array[index];
array[index] = array[j];
array[j] = temp;
index = j; //下标也要跟着走
}
}
}
/*插入排序:希尔排序,直接插入排序的升级版,也称为“缩小增量排序”
*基本原理:将待排序的数组元素分成多个子序列,使得每个子序列的元素个数相对较少,
*然后对各个子序列分别进行直接插入排序,待整个待排序列“基本有序”后,
*最后在对所有元素进行一次直接插入排序。
*希尔排序最好的时间复杂度和平均时间复杂度都是O(nlogn),最坏时间复杂度是O(n^2)
*由于记录是跳跃式的移动,希尔排序并不是一种稳定的排序算法。
*衡量算法是否稳定的标准:键值相同的元素排序前后相对次序不变。
*/
public void shellSortSmallToBig(int[] array) {
if(array.length == 0 || array.length == 1) return;
//每一次的增量折半,最后一次的增量为1
for(int increment = array.length / 2;increment >= 1;increment = increment / 2) {
//画图可以看出,针对分割线后面的每一个元素,不断地往前追踪比较
for(int i = increment;i < array.length;i ++) {
int temp = array[i];
int j = i - increment;
for(;j >= 0 && array[j] > temp;j -= increment) {
array[j + increment] = array[j];
}
array[j + increment] = temp;
}
System.out.println("增量是:" + increment);
for(int i : array) {
System.out.print(i + " ");
}
System.out.println();
}
}
/*选择排序:简单选择排序
*基本原理:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;
*然后在剩下的数当中再找最小的与第二个位置的数交换,
*如此循环到倒数第二个数和最后一个数比较为止。
*/
public void simpleSelectSort(int [] array) {
if(array.length == 0 || array.length == 1) return;
for(int i = 0;i < array.length - 1;i ++) {
int minIndex = i;
int minValue = array[i];
for(int j = i + 1;j < array.length;j ++) {
if(array[j] < minValue) {
minIndex = j;
minValue = array[j];
}
}
array[minIndex] = array[i];
array[i] = minValue;
}
}
/*选择排序:堆排序,时间复杂度O(nlogn),不稳定
*若要递增则建立大顶堆(根节点的值大于剩余所有节点的值),若要递减则建立小顶堆(根节点的值小于剩余所有节点的值)。
*基本原理:1.将数组构造成初始堆,从最后一个节点开始调整,得到初始堆。
*2.堆排序处理,交换堆顶的元素和最后一个元素,此时最后一个位置作为有序区;
*然后进行其他无序区的堆调整,重新得到大顶堆后,交换堆顶和倒数第二个元素的位置……
*/
public void heapSort(int [] array) {
if(array.length == 0 || array.length == 1) return;
//新建一个大顶堆
for(int i = array.length / 2;i >= 0;i --) {
adjustHeap(i, array.length, array); //新建大顶堆的时候根节点是数组中间节点及前半部分
System.out.println("初始化大顶堆:" + Arrays.toString(array));
}
//调整堆:交换堆顶和堆尾,然后除去堆尾重新调整大顶堆
for(int i = array.length - 1;i >= 0;i --) {
int temp = array[i];
array[i] = array[0];
array[0] = temp;
adjustHeap(0, i, array); //只需调整堆顶节点即可
System.out.println("调整大顶堆:" + Arrays.toString(array));
}
}
public void adjustHeap(int parent, int length, int [] array) { //根节点的位置以及欲调节的最大长度
int parentValue = array[parent];
int leftChild = 2 * parent + 1; //画图可得出此关系
while(leftChild < length) {
//右孩子存在且右孩子的值比左孩子的值大,则取右孩子
if(leftChild + 1 < length && array[leftChild + 1] > array[leftChild]) {
leftChild ++;
}
if(parentValue > array[leftChild]) {
break;
}
array[parent] = array[leftChild];
parent = leftChild;
leftChild = parent * 2 + 1;
}
array[parent] = parentValue; //往右找完了,将最开始的parentValue赋给最后一个父节点
}
/*交换排序:冒泡排序,平均时间复杂度O(n^2),稳定
*基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数
*自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。
*/
public void bubblingSort(int [] array) {
if(array.length == 0 || array.length == 1) return;
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]) { //小的排前面,大的一直往后冒
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
/*交换排序:快速排序,平均时间复杂度O(nlogn),不稳定
*基本思想:基于分治的思想,是冒泡排序的改进型。
*首先在数组中选择一个基准点(该基准点的选取可能影响快速排序的效率,后面讲解选取的方法),
*然后分别从数组的两端扫描数组,设两个指示标志(lo指向起始位置,hi指向末尾),
*首先从后半部分开始,如果发现有元素比该基准点的值小,就交换lo和hi位置的值,
*然后从前半部分开始扫秒,发现有元素大于基准点的值,就交换lo和hi位置的值,
*如此往复循环,直到lo>=hi,然后把基准点的值放到hi这个位置。一次排序就完成了。
*以后采用递归的方式分别对前半部分和后半部分排序,当前半部分和后半部分均有序时该数组就自然有序了。
*/
public int getMiddle(int [] array, int pHead, int pTail) {
//int base = array[pHead]; //固定切分的基准
int base = getBase2(array, pHead, pTail);
while(pHead < pTail) {
while(pHead < pTail && array[pTail] > base){
pTail --;
}
if(pHead >= pTail) {
break;
}
else {
int temp = array[pTail];
array[pTail] = array[pHead];
array[pHead] = temp;
pHead ++;
}
while(pHead < pTail && array[pHead] < base){
pHead ++;
}
if(pHead >= pTail) {
break;
}
else {
int temp = array[pHead];
array[pHead] = array[pTail];
array[pTail] = temp;
pTail --;
}
}
System.out.println(Arrays.toString(array) + " " + "pHead:" + pHead + " pTail:" + pTail);
return pHead;
}
//随机切分法获取基准元素:任意找一个元素与头交换
public int getBase(int [] array, int pHead, int pTail) {
//Math.random()范围是0-1
int randomIndex = (int)(Math.random() * (pTail - pHead) + pHead);
int temp = array[randomIndex];
array[randomIndex] = array[pHead];
array[pHead] = temp;
return array[pHead];
}
//三数取中法获取基准元素:头、中、尾先进行简单排序,再取头,可节省比较次数
public int getBase2(int [] array, int pHead, int pTail) {
int pMiddle = (pTail - pHead) / 2 + pHead;
if(array[pMiddle] > array[pTail]) {
int temp = array[pMiddle];
array[pMiddle] = array[pTail];
array[pTail] = temp;
}
if(array[pHead] > array[pTail]) {
int temp = array[pTail];
array[pTail] = array[pHead];
array[pHead] = temp;
}
if(array[pHead] > array[pMiddle]) {
int temp = array[pHead];
array[pHead] = array[pMiddle];
array[pMiddle] = temp;
}
return array[pHead];
}
public void fastSort(int [] array, int pHead, int pTail) {
if(array.length == 0 || array.length == 1) return;
if(pHead < pTail) {
int pMiddle = getMiddle(array, pHead, pTail);
fastSort(array, pHead, pMiddle - 1);
fastSort(array, pMiddle + 1, pTail);
}
}
/*归并排序:平均时间复杂度O(nlogn),稳定
*基本思想:将两个(或两个以上)有序表合并成一个新的有序表,
*即把待排序序列分为若干个子序列,每个子序列是有序的。
*然后再把有序子序列合并为整体有序序列。
*/
public void mergeSort(int [] array, int pHead, int pTail) {
if(array.length == 0 || array.length == 1) return;
if(pHead < pTail) {
int pMiddle = pHead + (pTail - pHead) / 2;
mergeSort(array, pHead, pMiddle);
mergeSort(array, pMiddle + 1, pTail);
mergeArray(array, pHead, pMiddle, pTail);
}
}
public void mergeArray(int[] array, int pHead, int pMiddle, int pTail) {
int [] tempArray = new int[pTail - pHead + 1];
int i = pHead; //前半段索引
int j = pMiddle + 1; //后半段索引
int k = 0; //辅助数组索引
while(i <= pMiddle && j <= pTail) {
if(array[i] < array[j]) {
tempArray[k ++] = array[i ++];
}
else {
tempArray[k ++] = array[j ++];
}
}
//经过上面循环,两个子数组里还会剩下一个最大的数,不确定是哪一个子数组
while(i <= pMiddle) {
tempArray[k ++] = array[i ++];
}
while(j <= pTail) {
tempArray[k ++] = array[j ++];
}
System.out.println(Arrays.toString(tempArray));
k = 0;
for(int t = pHead;t <= pTail;t ++) { //将辅助数组里的数据复制到原数组指定的位置
array[t] = tempArray[k ++];
}
}
public static void main(String[] args) {
ArraySort t = new ArraySort();
int [] array = {57, 68, 59, 52, 72, 28, 96, 33, 24, 19};
t.mergeSort(array, 0, array.length - 1);
// System.out.println(t.getBaseIndex(array, 0, array.length - 1));
// t.mergeSort(array, 0, array.length - 1);
for(int i : array) {
System.out.print(i + " ");
}
}
}