排序作为程序员的必修课是十分重要的,这篇文章主要包含快速排序、堆排序、冒泡排序、插入排序等
1.快速排序
public void quickSort(int[] arr,int begin,int end){
if (begin >= end)
{
return;
}
int i = begin;
int j = end;
int standard = arr[begin];//选择基准点
while (i < j){
while (i<j && arr[j]>standard){
j--;
}
arr[i] = arr[j];
while (i<j && arr[i] <= standard){
i++;
}
arr[j] = arr[i];
}
arr[i] = standard;
quickSort(arr,begin,i-1);
quickSort(arr,i+1,end);
}
//字符串数字排序如:“123456”和“456”,降序
public void quickSort(String[] arr,int begin,int end){
if (begin >= end)
{
return;
}
int i = begin;
int j = end;
int standard = Integer.parseInt(arr[begin]);
while (i < j){
while (i<j && Integer.parseInt(arr[j])<standard){
j--;
}
arr[i] = arr[j];
while (i<j && Integer.parseInt(arr[i]) >= standard){
i++;
}
arr[j] = arr[i];
}
arr[i] = ""+standard;
quickSort(arr,begin,i-1);
quickSort(arr,i+1,end);
}
2.堆排序
//交换
private void swap(int[] arr,int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//调整堆
private void heapAdjust(int[] arr,int i,int n){
int max = i;
if (2*i + 1 < n && arr[2*i + 1] > arr[max]){
max = 2*i + 1;
}
if (2*i + 2 < n && arr[2*i + 2] > arr[max]){
max = 2*i + 2;
}
if (max != i){
swap(arr,i,max);
heapAdjust(arr,max,n);
}
}
//初始化堆
private void initHeap(int[] arr,int n){
for (int i = n-1; i >= 0; i--) {
heapAdjust(arr,i,n);
}
}
//堆排序
public void heapSort(int[] arr, int n){
//初始化堆
initHeap(arr,n);
//开始排序
while (n > 0){
swap(arr,0,n-1);
heapAdjust(arr,0,n - 1);
n--;
}
}
3.插入排序
//交换
private void swap(int[] arr,int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//插入排序
public void insertSort(int[] arr){
int n = arr.length;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (arr[i] < arr[j]){
int temp = arr[i];
for (int k = i; k > j; k--) {
arr[k] = arr[k-1];
}
arr[j] = temp;
break;
}
}
}
}
//二分搜索插入排序
public void insertSortBinarSearch(int[] arr){
int n = arr.length;
for (int i = 1; i < n; i++) {
int low = 0;
int high = i-1;
while (low <= high){
int mid = (low + high)/2;
if (arr[i] < arr[mid]){
high = mid - 1;
}else {
low = mid +1;
}
}
int temp = arr[i];
for (int k = i; k > high + 1; k--) {
arr[k] = arr[k-1];
}
arr[high + 1] = temp;
}
}
4.冒泡排序(性能很低)
//交换
private void swap(int[] arr,int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//冒泡排序
public void bubbleSort(int[] arr){
int n = arr.length;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n - i -1; j++) {
if (arr[j] > arr[j+1]){
swap(arr,j,j+1);
}
}
}
}
//冒泡排序优化
public void bubbleSortOpt(int[] arr){
int n = arr.length;
boolean flag = true;//用于标记一次遍历有没有交换,如果没有直接退出
for (int i = 0; i < n; i++) {
flag = true;
for (int j = 0; j < n - i -1; j++) {
if (arr[j] > arr[j+1]){
flag = false;
swap(arr,j,j+1);
}
}
if (flag){
return;
}
}
}
5.希尔排序(不知道怎么回事测试这个排序的时候时间会比插入排序还要长)
//希尔排序,步长变化的插入排序
private void shellSort(int[] arr,int legth){
for (int i = legth; i < arr.length; i++) {
for (int j = i - i/legth*legth; j < i ; j= j+legth) {
if (arr[i] < arr[j]){
int temp = arr[i];
for (int k = i; k > j ; k = k - legth) {
arr[k] = arr[k - legth];
}
arr[j] = temp;
break;
}
}
}
}
public void shell(int[] arr){
// int n = (arr.length+1)/2 - 1;
// if (n>pathLength.length) n = pathLength.length - 1;
int n = arr.length/2;
for (int i = n; i > 0 ; i= i /2) {
shellSort(arr,i);
}
}
6.测试:
public static void main(String[] args) {
int n = 100000;
int[] arrays = new int[n];
for (int i = 0; i < n; i++) {
arrays[i] = (int)(Math.random()*n + 1);
}
long start = 0;
//测试堆排
int[] arraysHeap = arrays.clone();
HeapSort heapSort = new HeapSort();
start = System.currentTimeMillis();
heapSort.heapSort(arraysHeap,n);
System.out.println("堆排时间:"+(System.currentTimeMillis() - start));//+" "+Arrays.toString(arraysHeap));
//测试快排
int[] arraysQuick = arrays.clone();
QuickSort quickSort = new QuickSort();
start = System.currentTimeMillis();
quickSort.quickSort(arraysQuick,0,n-1);
System.out.println("快排时间:"+(System.currentTimeMillis() - start));//+" "+Arrays.toString(arraysQuick));
//测试希尔排序
int[] arraysShell= arrays.clone();
ShellSort shellSort = new ShellSort();
start = System.currentTimeMillis();
shellSort.shell(arraysShell);
System.out.println("希尔排序时间:"+(System.currentTimeMillis() - start));//+" "+Arrays.toString(arraysShell));
//测试插入排序
int[] arraysInsert = arrays.clone();
InsertSort insertSort = new InsertSort();
start = System.currentTimeMillis();
insertSort.insertSort(arraysInsert);
System.out.println("插入排序时间:"+(System.currentTimeMillis() - start));//+" "+Arrays.toString(arraysInsert));
//二分插入排序
int[] arraysInsertBin = arrays.clone();
start = System.currentTimeMillis();
insertSort.insertSortBinarSearch(arraysInsertBin);
System.out.println("优化插入排序时间:"+(System.currentTimeMillis() - start));//+" "+Arrays.toString(arraysInsertBin));
//冒泡排序优化
int[] arraysBubbleOpt = arrays.clone();
BubbleSort bubbleSort = new BubbleSort();
start = System.currentTimeMillis();
bubbleSort.bubbleSortOpt(arraysBubbleOpt);
System.out.println("优化冒泡时间:"+(System.currentTimeMillis() - start));//+" "+Arrays.toString(arraysBubbleOpt));
//测试冒泡排序
int[] arraysBubble = arrays.clone();
start = System.currentTimeMillis();
bubbleSort.bubbleSort(arraysBubble);
System.out.println("普通冒泡时间:"+(System.currentTimeMillis() - start));//+" "+Arrays.toString(arraysBubble));
}
结果:
我在做测试的时候发现了一个问题,那就是由于快速排序和堆排序采用了递归的思想,因此如果当原始数据是完全逆序的,也就是说当你要把数据变成升序但是原始数据是降序的时候,如果数据量过大,那么就可能出现栈溢出的异常,经过我的测试,大概在300000个完全逆序的数的时候堆排序和快速排序就会产生栈溢出(这个数字应该是和JVM的虚拟机栈的大小设置有关,可以通过调整栈大小来提高或减小这个值)