很多代码都是参照CSDN上的,我只是简单的总结了一下,由于这是很早之前写的程序,参考的帖子都没有记,参考的文章也非常多,所以这次就不列出参考的帖子了。感谢现在发达的互联网,让知识传播的代价越来越小。
/**
* Created by lwc on 4/28/16.
*/
//选择排序(直接选择排序,堆排序)
//交换排序(冒泡排序,快速排序)
//插入排序(直接插入排序,折半插入排序,Shell排序)
//归并排序
//桶式排序
//基数排序
public class Sort {
static int[] array = new int[]{1, 2, 33, 0, 5, 6, 9, 100, 67, 99, 90};
public static void main(String[] args) {
Sort.insertSort(array);
Sort.binaryInsertSort(array);
Sort.shellInsertSort(array);
Sort.bubbleSort(array);
Sort.quickSort(array, 0, array.length - 1);
Sort.selectSort(array);
Sort.heapSort(array);
for (int i : array) {
System.out.println(i);
}
}
public static void insertSort(int[] array1) {
// 插入排序法--直接插入排序
// 思想:插入排序法的排序思想就是从数组的第二个元素开始,将数组中的每一个元素按照规则插入到已排好序的数组中以达到排序的目的.
// 一般情况下将数组的第一个元素作为启始元素,从第二个元素开始依次插入.由于要插入到的数组是已经排好序的,
// 所以只是要从右向左找到比插入点(下面程序中的insertNote)小(对升序而言)的第一个数组元素就插入到其后面.
// 直到将最后一个数组元素插入到数组中,整个排序过程就算完成.
// 稳定性:稳定的.
// 时间复杂度:O(n2)
int[] array = array1;
int insertNode; //The integer number to insert from 1 to n-1
for(int i = 1; i < array.length; i++) {
insertNode = array[i];
int j = i - 1;
while(j >= 0 && insertNode < array[j]) {
array[j+1] = array[j];//put the number to the next place until get the right place
j--;
}
array[j+1] = insertNode;//Insert the number to the right place
}
}
//插入排序--折半插入排序
//折半插入排序法,又称二分插入排序法,是直接插入排序法的改良版,也需要执行i-1趟插入,
//不同之处在于,第i趟插入,先找出第i+1个元素应该插入的的位置,假定前i个数据是已经处于有序状态
public static void binaryInsertSort(int[] array1) {
int[] array = array1;
int insertNode;// The integer number to insert from 1 to n-1
for(int i = 1; i < array.length; i++) {
insertNode = array[i];
int low = 0;
int hight = i - 1;
while(low <= hight) {
int mid = (low + hight)/2;
if(array[mid] > insertNode) {
hight = mid - 1;
} else {
low = mid + 1;
}
}
for(int j = i; j > low; j--) {
array[j] = array[j - 1];
}
array[low] = insertNode;
}
}
//插入排序--希尔排序(Shell排序)
//希尔排序(缩小增量法) 属于插入类排序,由Shell提出,希尔排序对直接插入排序进行了简单的改进:
//它通过加大插入排序中元素之间的间隔,并在这些有间隔的元素中进行插入排序,从而使数据项大跨度地移动,
//当这些数据项排过一趟序之后,希尔排序算法减小数据项的间隔再进行排序,依次进行下去,进行这些排序时的数据项之间的间隔被称为增量,
//习惯上用字母h来表示这个增量。
//常用的h序列由Knuth提出,该序列从1开始,通过如下公式产生:
//h = 3 * h +1
//反过来程序需要反向计算h序列,应该使用
//h=(h-1)/3
//Shell排序是不稳定的,它的空间开销也是O(1),时间开销估计在O(N3/2)~O(N7/6)之间
public static void shellInsertSort(int[] array1) {
int[] array = array1;
int insertNode;
//get the maximum of h
int h = 1;
while(h <= array.length/3) {
h = 3 * h + 1;
}
while(h > 0) {
for(int i = h; i < array.length; i++) {
if(array[i] < array[i - h]) {
insertNode = array[i];
int j = i - h;
while(j >= 0 && array[j] > insertNode) {
array[j + h] = array[j];
j = j - h;
}
array[j + h] = insertNode;
}
}
h = (h - 1)/3;
}
}
//交换排序--冒泡排序。它的时间复杂度为O(n^2),虽然不及堆排序、快速排序的O(nlogn,底数为2)
public static void bubbleSort(int[] array1) {
int[] array = array1;
for(int i = 0; i < array.length - 1; i++) {
boolean isSorted = true;
for(int j = 0; j < array.length - i - 1; j++) {
if(array[j] > array[j +1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
isSorted = false;
}
}
if(isSorted) {
break;
}
}
}
//交换排序--快速排序
//快速排序是一个速度非常快的交换排序算法,它的基本思路很简单,从待排的数据序列中任取一个数据(如第一个数据)作为分界值,所有比它小的数据元素放到左边,所有比它大的数据元素放到它的右边。经过这样一趟下来,该序列形成左右两个子序列,左边序列中的数据元素的值都比分界值小,右边序列中数据元素的值都比分界值大。
//接下来对左右两个子序列进行递归排序,对两个子序列重新选择中心元素并依此规则调整,直到每个元素子表的元素只剩下一个元素,排序完成。
//思路:
//1.定义一个i变量,i变量从左边第一个索引开始,找大于分界值的元素的索引,并用i来记录它。
//2.定义一个j变量,j变量从右边第一个索引开始,找小于分界值的元素的索引,并用j来记录它。
//3.如果i<j,交换i,j两个索引处的元素。
//重复执行以上1,2,3步,直到i>=j,可以判断j左边的数据元素都小于分界值,j右边的数据元素都大于分界值,最后将分界值和j索引处的元素交换即可。
//时间复杂度
//最好情况(每次总是选到中间值作枢轴)T(n)=O(nlogn)
//最坏情况(每次总是选到最小或最大元素作枢轴)
//做n-1趟,每趟比较n-i次,总的比较次数最大:[O(n²)]
//平均时间复杂度为::T(n)=O(nlogn)
public static void quickSort(int[] array1, int start, int end) {
int[] array = array1;
if(start >= end) {
return;
}
int pivot = array[start];
int i = start + 1;
int j = end;
while(true) {
while(i <= end && array[i] < pivot) {
i++;
}
while(j > start && array[j] > pivot) {
j--;
}
if(i < j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
} else {
break;
}
}
int temp = array[j];
array[j] = array[start];
array[start] = temp;
quickSort(array, start, j - 1);
quickSort(array, j + 1, end);
}
//选择排序--直接选择排序
//直接选择排序的基本操作就是每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,
//直到全部待排序的数据元素排完,它需要经过n-1趟比较。算法不稳定,O(1)的额外的空间,比较的时间复杂度为O(n^2)
//,交换的时间复杂度为O(n),并不是自适应的。在大多数情况下都不推荐使用。只有在希望减少交换次数的情况下可以用。
public static void selectSort(int[] array1) {
int[] array = array1;
for(int i = 0; i < array.length - 1; i++) {
int minIndex = i;
for(int j = i + 1;j < array.length; j++) {
if(array[j] < array[minIndex]) {
minIndex = j;
}
}
int temp = array[i];
array[i] = array[minIndex];
array[minIndex] = temp;
}
}
//选择排序--堆积排序(Heapsort)是指利用堆积树(堆)这种资料结构所设计的一种排序算法,可以利用数组的特点快速定位指定索引的元素。
//堆排序是不稳定的排序方法,辅助空间为O(1), 最坏时间复杂度为O(nlog2n) ,堆排序的堆序的平均性能较接近于最坏性能。
//堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。
//① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
//② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],
//且满足R[1..n-1].keys≤R[n].key
//③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。
//然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,
//由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
public static void heapSort(int[] array1) {
<span style="white-space:pre"> </span>int[] array = array1;
<span style="white-space:pre"> </span>buildMaxHeap(array, array.length);
<span style="white-space:pre"> </span>for(int i = array.length - 1; i > 0; i--) {
<span style="white-space:pre"> </span>int temp = array[i];
<span style="white-space:pre"> </span>array[i] = array[0];
<span style="white-space:pre"> </span>array[0] = temp;
<span style="white-space:pre"> </span>maxHeapify(array, 1, i);
<span style="white-space:pre"> </span>}
}
//when the root is removed, change to max heap
public static void maxHeapify(int[] array, int parentIndex, int length) {
<span style="white-space:pre"> </span>int left = 2 * parentIndex;
<span style="white-space:pre"> </span>int right = 2 * parentIndex + 1;
<span style="white-space:pre"> </span>int largestNode = parentIndex;
<span style="white-space:pre"> </span>if(left <= length && array[left - 1] > array[parentIndex - 1]) {
<span style="white-space:pre"> </span>largestNode = left;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>if(right <= length && array[right - 1] > array[largestNode - 1]) {
<span style="white-space:pre"> </span>largestNode = right;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>if(largestNode != parentIndex) {
<span style="white-space:pre"> </span>int temp = array[largestNode - 1];
<span style="white-space:pre"> </span>array[largestNode - 1] = array[parentIndex - 1];
<span style="white-space:pre"> </span>array[parentIndex - 1] = temp;
<span style="white-space:pre"> </span>maxHeapify(array, largestNode, length);
<span style="white-space:pre"> </span>}
}
//build a max heap
public static void buildMaxHeap(int[] array, int length) {
<span style="white-space:pre"> </span>for(int i = length / 2; i > 0; i--) {
<span style="white-space:pre"> </span>maxHeapify(array, i, length);
<span style="white-space:pre"> </span>}
}
//归并排序(Merge)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
//
//归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
//
//归并排序算法稳定,数组需要O(n)的额外空间,链表需要O(log(n))的额外空间,时间复杂度为O(nlog(n)),算法不是自适应的,不需要对数据的随机读取。
//
//工作原理:
//
//1、申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
//
//2、设定两个指针,最初位置分别为两个已经排序序列的起始位置
//
//3、比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
//
//4、重复步骤3直到某一指针达到序列尾
//
//5、将另一序列剩下的所有元素直接复制到合并序列尾
public static int[] mergeSort(int[] nums, int low, int high) {
<span style="white-space:pre"> </span>int mid = (low + high) / 2;
<span style="white-space:pre"> </span>if(low < high) {
<span style="white-space:pre"> </span>mergeSort(nums, low, mid);
<span style="white-space:pre"> </span>mergeSort(nums, mid + 1, high);
<span style="white-space:pre"> </span>merge(nums, low, mid, high);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return nums;
}
public static void merge(int[] nums, int low, int mid, int high) {
<span style="white-space:pre"> </span>int[] temp = new int[high - low + 1];
<span style="white-space:pre"> </span>int i = low;
<span style="white-space:pre"> </span>int j = mid + 1;
<span style="white-space:pre"> </span>int k = 0;
<span style="white-space:pre"> </span>while(i <= mid && j <= high) {
<span style="white-space:pre"> </span>if(nums[i] < nums[j]) {
<span style="white-space:pre"> </span>temp[k++] = nums[i++];
<span style="white-space:pre"> </span>} else {
<span style="white-space:pre"> </span>temp[k++] = nums[j++];
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>while(i <= mid) {
<span style="white-space:pre"> </span>temp[k++] = nums[i++];
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>while(j <= high) {
<span style="white-space:pre"> </span>temp[k++] = nums[j++];
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>for(int k2 = 0; k2 < (high - low + 1); k2++) {
<span style="white-space:pre"> </span>nums[low + k2] = temp[k2];
<span style="white-space:pre"> </span>}
}
}