一、冒泡排序-稳定:
思路:从第一个元素开始,比较每对相邻元素,如果第一个比第二个大,则交换位置。
一轮相邻元素两两相比后,在最后一个位置的就是最大值。
再接着第二轮相邻元素两两相比,在倒数第二个位置就是第二最大值。
这样经过n轮之后就排序好了。
/**
* 冒泡排序-稳定:
*
* 从第一个元素开始,比较每对相邻元素,如果第一个比第二个大,则交换位置。
* 一轮相邻元素两两相比后,在最后一个位置的就是最大值。
* 再接着第二轮相邻元素两两相比,在倒数第二个位置就是第二最大值。
* 这样经过n轮之后就排序好了
*
* @param array
*/
public static void bubbleSort(int[] array){
if(array!=null && array.length>0){
int n = array.length;
for(int i=0;i<n;i++){
for(int j=0;j<n-1-i;j++){
if(array[j]>array[j+1]){
int t = array[j];
array[j] = array[j+1];
array[j+1] = t;
}
}
}
}
}
二、选择排序-不稳定:
思路:从第一个元素开始,将第一个元素和后面的元素依次比较,如果第一个元素大于当前元素,则交换位置。
一轮比较之后,第一个位置就会是最小值。
接着从第二个元素开始,将第二个元素和后面的元素依次比较,如果第二个元素大于当前元素,则交换位置。
这一轮比较之后,第二个位置就会是第二最小值。
这样经过n-1轮比较之后就排序好了
/**
* 选择排序-不稳定:
*
* 从第一个元素开始,将第一个元素和后面的元素依次比较,如果第一个元素大于当前元素,则交换位置。
* 一轮比较之后,第一个位置就会是最小值。
* 接着从第二个元素开始,将第二个元素和后面的元素依次比较,如果第二个元素大于当前元素,则交换位置。
* 这一轮比较之后,第二个位置就会是第二最小值。
* 这样经过n-1轮比较之后就排序好了
*
* @param array
*/
public static void selectionSort(int[] array){
if(array!=null &&array.length>0){
int n = array.length;
for(int i=0;i<n-1;i++){
int minIndex = i;
for(int j=i+1;j<n;j++){
if(array[minIndex]>array[j]){
minIndex = j;
}
}
if(minIndex!=i){
int t = array[i];
array[i] = array[minIndex];
array[minIndex] = t;
}
}
}
}
三、插入排序-稳定:在已经排好序的元素里面从后往前比较,插入对应的位置。
思路:第一个元素(这个元素已排好序,因为这是第一个元素)
从第二个元素开始,在已经排好序的元素里面 从后往前依次比较,如果第二个元素小于当前元素,则插入当前元素前面。
从第三个元素开始,在已经排好序的元素里面 从后往前依次比较,如果第三个元素小于当前元素,则插入当前元素前面。
这样重复之后就排序好了
/**
* 插入排序-稳定:在已经排好序的元素里面从后往前比较,插入对应的位置。
*
* 第一个元素(这个元素已排好序,因为这是第一个元素)
* 从第二个元素开始,在已经排好序的元素里面 从后往前依次比较,如果第二个元素小于当前元素,则插入当前元素前面。
* 从第三个元素开始,在已经排好序的元素里面 从后往前依次比较,如果第三个元素小于当前元素,则插入当前元素前面。
* 这样重复之后就排序好了
*
* @param array
*/
public static void insertionSort(int[] array){
if(array!=null && array.length>0){
int n = array.length;
for(int i=1;i<n;i++){
int temp = array[i];
for(int j=i-1;j>=0;j--){
if(temp<array[j]){
array[j+1] = array[j];
array[j] = temp;
}
}
}
}
}
四、希尔排序-不稳定:
思路:确定一个增量序列 [t1,t2,…,tk],tk=1
根据增量序列的个数k,做k趟 插入排序
每趟排序,根据对应的增量ti(元素间隔)分成一组,这一组里面的元素做直接插入排序。
当增两ti=1的时候,元素间隔是1,其实就是直接插入排序
/**
* 希尔排序-不稳定:
*
* 确定一个增量序列 [t1,t2,…,tk],tk=1
* 根据增量序列的个数k,做k趟 插入排序
* 每趟排序,根据对应的增量ti(元素间隔)分成一组,这一组里面的元素做直接插入排序。
* 当增两ti=1的时候,元素间隔是1,其实就是直接插入排序,
*
* @param array
*/
public static void shellSort(int[] array){
if(array!=null && array.length>0){
int n = array.length;
int gap = 1;
int gapLen = 1;
while( gap<n/3 ){
gap = 3*gap+1;
gapLen++;
}
//确定增量序列
int[] gapArray = new int[gapLen];
for(int i=0;i<gapLen;i++){
gapArray[i] = gap;
gap/=3;
}
System.out.print("增量序列:");
print(gapArray);
for(int i=0;i<gapLen;i++){
//做每组的直接插入排序
for(int j=gapArray[i];j<n;j+=gapArray[i]){
int temp = array[j];
for(int k=j-gapArray[i];k>=0;k-=gapArray[i]){
if(temp<array[k]){
array[ k+gapArray[i] ] = array[k];
array[k] = temp;
}
}
}
}
}
}
五、归并排序-稳定:(分治思想,二分)
思路:将元素分成2组,这2组又分别可以再分2组,直到组合两组组里面只剩一个元素,再将两组两个元素合并成有序。
/**
* 归并排序-稳定:(分治思想,二分)
* 将元素分成2组,这2组又分别可以再分2组,直到组合两组组里面只剩一个元素,再将两组两个元素合并成有序
*
* @param array
*/
public static int[] mergeSort(int[] array){
if(array.length<2){
return array;
}
int n = array.length;
int mid = n/2;
int[] left = Arrays.copyOfRange(array,0,mid);
int[] right = Arrays.copyOfRange(array,mid,n);
return merge(mergeSort(left),mergeSort(right));
}
public static int[] merge(int[] left,int[] right){
int leftLen = left.length;
int rightLen = right.length;
int[] merge = new int[leftLen+rightLen];
int i=0,j=0,k=0;
while(i<leftLen && j<rightLen ){
if(left[i]<right[j]){
merge[k++] = left[i++];
}else{
merge[k++] = right[j++];
}
}
while(i<leftLen){
merge[k++]=left[i++];
}
while(j<rightLen){
merge[k++]=right[j++];
}
return merge;
}
六、快排-不稳定
思路:首先找到一个基准,然后将所有小于基准的元素放到基准左边,所有大的放到基准右边
这个时候,基准左边的元素都比基准小,右边的都比基准大
接着又分别将基准左边的元素、右边的元素 重复上面操作
/**
* 快排-不稳定
* 首先找到一个基准,然后将所有小于基准的元素放到基准左边,所有大的放到基准右边
* 这个时候,基准左边的元素都比基准小,右边的都比基准大
* 接着又分别将基准左边的元素、右边的元素 重复上面操作
*
* @param array
*/
public static void quickSort(int[] array,int left,int right){
if(left>=right){
return ;
}
int temp = array[left];
int n = right;
while(left<right){
while( left<right && array[right]>=temp ){
right--;
}
if(left<right){
array[left++] = array[right];
}
while( left<right && array[left]<=temp ){
left++;
}
if(left<right){
array[right--]=array[left];
}
}
array[left] = temp;
quickSort(array,0,left-1);
quickSort(array,left+1,n);
}
七、堆排序-不稳定:构造小顶堆,调整小顶堆的过程
思路:小顶堆:每个父节点的值都比左右孩子值都小的完全二叉树,根值是最小的
父节点和左右孩子的位置关系:
父节点的位置:i (从0开始)
左孩子的位置:2*i+1
有孩子的位置:2*i+2
/**
* 堆排序-不稳定:构造小顶堆,调整小顶堆的过程
* 小顶堆:每个父节点的值都比左右孩子值都小的完全二叉树,根值是最小的
* 父节点和左右孩子的位置关系:
* 父节点的位置:i (从0开始)
* 左孩子的位置:2*i+1
* 有孩子的位置:2*i+2
*
* @param array
*/
public static void heapSort(int[] array){
int n = array.length;
//建立初堆
for(int i=n/2-1;i>=0;i--){
heapAdjust(array,i,n);
}
//调整堆
for(int i=n-1;i>0;i--){
int t = array[0];
array[0] = array[i];
array[i] = t;
heapAdjust(array,0,i);
}
}
public static void heapAdjust(int[] array,int i,int n){
for(int j=i;j<n;j++){
int left = 2*j+1;
int right = 2*j+2;
if(left<n){
if(array[j]>array[left]){
int t = array[j];
array[j]=array[left];
array[left]=t;
}
}
if(right<n){
if(array[j]>array[right]){
int t = array[j];
array[j] = array[right];
array[right] = t;
}
}
}
}
所有:
/**排序算法
* @author chen jia hao
*/
public class SortTest {
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()){
int n = scanner.nextInt();
scanner.nextLine();
int[] array = new int[n];
for(int i=0;i<n;i++){
array[i] = scanner.nextInt();
}
//bubbleSort(array);
// selectionSort(array);
// insertionSort(array);
// shellSort(array);
//array = mergeSort(array);
//quickSort(array,0,n-1);
heapSort(array);
print(array);
}
}
/**
* 冒泡排序-稳定:
*
* 从第一个元素开始,比较每对相邻元素,如果第一个比第二个大,则交换位置。
* 一轮相邻元素两两相比后,在最后一个位置的就是最大值。
* 再接着第二轮相邻元素两两相比,在倒数第二个位置就是第二最大值。
* 这样经过n轮之后就排序好了
*
* @param array
*/
public static void bubbleSort(int[] array){
if(array!=null && array.length>0){
int n = array.length;
for(int i=0;i<n;i++){
for(int j=0;j<n-1-i;j++){
if(array[j]>array[j+1]){
int t = array[j];
array[j] = array[j+1];
array[j+1] = t;
}
}
}
}
}
/**
* 选择排序-不稳定:
*
* 从第一个元素开始,将第一个元素和后面的元素依次比较,如果第一个元素大于当前元素,则交换位置。
* 一轮比较之后,第一个位置就会是最小值。
* 接着从第二个元素开始,将第二个元素和后面的元素依次比较,如果第二个元素大于当前元素,则交换位置。
* 这一轮比较之后,第二个位置就会是第二最小值。
* 这样经过n-1轮比较之后就排序好了
*
* @param array
*/
public static void selectionSort(int[] array){
if(array!=null &&array.length>0){
int n = array.length;
for(int i=0;i<n-1;i++){
int minIndex = i;
for(int j=i+1;j<n;j++){
if(array[minIndex]>array[j]){
minIndex = j;
}
}
if(minIndex!=i){
int t = array[i];
array[i] = array[minIndex];
array[minIndex] = t;
}
}
}
}
/**
* 插入排序-稳定:在已经排好序的元素里面从后往前比较,插入对应的位置。
*
* 第一个元素(这个元素已排好序,因为这是第一个元素)
* 从第二个元素开始,在已经排好序的元素里面 从后往前依次比较,如果第二个元素小于当前元素,则插入当前元素前面。
* 从第三个元素开始,在已经排好序的元素里面 从后往前依次比较,如果第三个元素小于当前元素,则插入当前元素前面。
* 这样重复之后就排序好了
*
* @param array
*/
public static void insertionSort(int[] array){
if(array!=null && array.length>0){
int n = array.length;
for(int i=1;i<n;i++){
int temp = array[i];
for(int j=i-1;j>=0;j--){
if(temp<array[j]){
array[j+1] = array[j];
array[j] = temp;
}
}
}
}
}
/**
* 希尔排序-不稳定:
*
* 确定一个增量序列 [t1,t2,…,tk],tk=1
* 根据增量序列的个数k,做k趟 插入排序
* 每趟排序,根据对应的增量ti(元素间隔)分成一组,这一组里面的元素做直接插入排序。
* 当增两ti=1的时候,元素间隔是1,其实就是直接插入排序,
*
* @param array
*/
public static void shellSort(int[] array){
if(array!=null && array.length>0){
int n = array.length;
int gap = 1;
int gapLen = 1;
while( gap<n/3 ){
gap = 3*gap+1;
gapLen++;
}
//确定增量序列
int[] gapArray = new int[gapLen];
for(int i=0;i<gapLen;i++){
gapArray[i] = gap;
gap/=3;
}
System.out.print("增量序列:");
print(gapArray);
for(int i=0;i<gapLen;i++){
//做每组的直接插入排序
for(int j=gapArray[i];j<n;j+=gapArray[i]){
int temp = array[j];
for(int k=j-gapArray[i];k>=0;k-=gapArray[i]){
if(temp<array[k]){
array[ k+gapArray[i] ] = array[k];
array[k] = temp;
}
}
}
}
}
}
/**
* 归并排序-稳定:(分治思想,二分)
* 将元素分成2组,这2组又分别可以再分2组,直到组合两组组里面只剩一个元素,再将两组两个元素合并成有序
*
* @param array
*/
public static int[] mergeSort(int[] array){
if(array.length<2){
return array;
}
int n = array.length;
int mid = n/2;
int[] left = Arrays.copyOfRange(array,0,mid);
int[] right = Arrays.copyOfRange(array,mid,n);
return merge(mergeSort(left),mergeSort(right));
}
public static int[] merge(int[] left,int[] right){
int leftLen = left.length;
int rightLen = right.length;
int[] merge = new int[leftLen+rightLen];
int i=0,j=0,k=0;
while(i<leftLen && j<rightLen ){
if(left[i]<right[j]){
merge[k++] = left[i++];
}else{
merge[k++] = right[j++];
}
}
while(i<leftLen){
merge[k++]=left[i++];
}
while(j<rightLen){
merge[k++]=right[j++];
}
return merge;
}
/**
* 快排-不稳定
* 首先找到一个基准,然后将所有小于基准的元素放到基准左边,所有大的放到基准右边
* 这个时候,基准左边的元素都比基准小,右边的都比基准大
* 接着又分别将基准左边的元素、右边的元素 重复上面操作
*
* @param array
*/
public static void quickSort(int[] array,int left,int right){
if(left>=right){
return ;
}
int temp = array[left];
int n = right;
while(left<right){
while( left<right && array[right]>=temp ){
right--;
}
if(left<right){
array[left++] = array[right];
}
while( left<right && array[left]<=temp ){
left++;
}
if(left<right){
array[right--]=array[left];
}
}
array[left] = temp;
quickSort(array,0,left-1);
quickSort(array,left+1,n);
}
/**
* 堆排序-不稳定:构造小顶堆,调整小顶堆的过程
* 小顶堆:每个父节点的值都比左右孩子值都小的完全二叉树,根值是最小的
* 父节点和左右孩子的位置关系:
* 父节点的位置:i (从0开始)
* 左孩子的位置:2*i+1
* 有孩子的位置:2*i+2
*
* @param array
*/
public static void heapSort(int[] array){
int n = array.length;
//建立初堆
for(int i=n/2-1;i>=0;i--){
heapAdjust(array,i,n);
}
//调整堆
for(int i=n-1;i>0;i--){
int t = array[0];
array[0] = array[i];
array[i] = t;
heapAdjust(array,0,i);
}
}
public static void heapAdjust(int[] array,int i,int n){
for(int j=i;j<n;j++){
int left = 2*j+1;
int right = 2*j+2;
if(left<n){
if(array[j]>array[left]){
int t = array[j];
array[j]=array[left];
array[left]=t;
}
}
if(right<n){
if(array[j]>array[right]){
int t = array[j];
array[j] = array[right];
array[right] = t;
}
}
}
}
public static void print(int[] array){
if(array!=null && array.length>0){
for(int i=0,len=array.length-1;i<len;i++){
System.out.print(array[i]+" ");
}
System.out.println(array[array.length-1]);
}
}
}