排序算法整理

稳定的排序:冒泡,插入,选择,归并排序
不稳定的排序:希尔,堆排,快排

1.插入排序 —-稳定的排序,O(n^2)

首先讲插入排序是因为,希尔排序由插入排序改进而来。

下面代码通过画图的方式来理解。i依次从0位开始遍历,比较data[i]和data[i+1]的大小,如果data[i]>data[i+1]则需要将data[i+1]的值插入到前面合适的位置,令j=i,让j依次往前遍历,当data[j]>temp,将数据后移;当j移动到最前面或者有data[j]

public static void InsertSort(int [] data){

        int temp,j;
        for(int i =0;i<data.length;i++){
            if(data[i]>data[i+1]){
                temp = data[i+1];
                for(j = i;(j>=0)&&data[j]>temp;j--){
                    data[j+1]=data[j];//向后移动
                }
                data[j+1]=temp;         
            }
        }
    }

2.希尔排序 —O(n^1.5)

希尔排序可以理解为插入排序的改进版,只是将插入排序的间隔1的比较改成动态的gap,实现组内有序,通过缩小gap的多次遍历,达到最终的全局有序。

public static void ShellSort(int []data){
int i,j,temp;
        int gap = data.length;
        do{
            gap = gap/3+1;

            for(i=0;i<data.length-gap;i++){
                if(data[i]>data[i+gap]){
                    temp = data[i+gap];
                    for(j=i;(j>=0)&&data[j]>temp;j-=gap){
                        data[j+gap]=data[j];
                    }
                    data[j+gap]=temp;
                }
            }

        }while(gap >1);

}

3.堆排序 —O(nlogn)

堆排序的基本思想是,将待排序的序列构造成一个大顶堆,此时,堆顶的根节点就是最大元素,将其与最后一个元素交换,重新将前N-1个元素构造大顶堆。如此反复执行,便可排序。
注意:按最大堆来说,父节点比孩子节点大,但是左右孩子大小不一定。大顶堆是一个完全二叉树,满足父节点序号为i,其子节点序号为2*i,2*i+1。

public static void heapSort(int [] data){
    int n= data.length;
    //创建初始最大堆
    for(int i=n/2;i>0;i--){
        maxHeap(data,i,n);
    }
    //循环n-1次
    for(int i=n-1;i>0;i--){
        swap(data,0,i);//将大顶堆的最大元素放到最后面
        maxHeap(data,1,i);
    //  System.out.println(Arrays.toString(data));
    }

}
public static void maxHeap(int [] data,int i,int heapsize){
    int left=2*i;
    int right=left+1;
    int largest=i;

    if((left<=heapsize)&&(data[left-1]>data[largest-1]))
        largest=left;
    if((right<=heapsize)&&(data[right-1]>data[largest-1]))
        largest=right;
    if(largest!=i){
        swap(data,largest-1,i-1);
        maxHeap(data,largest,heapsize);//递归更新
    }
}

4.归并排序 —O(nlogn) 稳定

递归方式:

//递归拆解方式
private static void sort(int[] data, int[] temp, int low, int high) {
        int mid = (low+high)/2;
        if(low<high){
            sort(data,temp,low,mid);
            sort(data,temp,mid+1,high);
            merge(data,temp, low, mid, high);
        }           
    }
     /** 
     * 将两个数组进行归并,归并前面2个数组已有序,归并后依然有序 
     * @param data    数组对象 
     * @param low     左数组的第一个元素的索引 
     * @param mid     左数组的最后一个元素的索引,mid+1是右数组第一个元素的索引 
     * @param high    右数组最后一个元素的索引 
     */  
    private static void merge(int []data,int []temp,int low,int mid,int high){
        int i=low;
        int j=mid+1;//data的右边的游标
        int k=low;//标识temp的游标

        while(i<=mid&&j<=high){
            if(data[i]<data[j])
                temp[k++] = data[i++];
            else
                temp[k++]= data[j++];
        }
        while(i<=mid)//把左边剩余的移到temp
            temp[k++]=data[i++];
        while(j<=high)//右边剩余的移到temp
            temp[k++]=data[j++];

        //把temp中的排序后的内容覆盖data中的数据
        while(low<=high)
            data[low]=temp[low++];

    }

5.快速排序 —O(nlogn),最坏O(n^2)

基础代码:

public static void Qsort(int []data,int low ,int high){
    if(low<high){
        int pivot = partition(data,low,high);
        Qsort(data,low,pivot-1);
        Qsort(data,pivot+1,high);
    }
}
public static void partition(int []data,int low ,int high){
    int pivotkey = data[low];
    while(low<high){
        while((low<high)&&(data[high]>=pivotkey))
            high--;
        swap(data,low,high);
        while((low<high)&&(data[low]<=pivotkey))
            low++;
        swap(data,low,high);
    }
    return low;
}

优化代码一(减少不必要的交换):

public static void Qsort(int[] data,int low,int high){
    if(low<high){
        int pivot = partition(data,low,high);
        Qsort(data,low,pivot-1);
        Qsort(data,pivot+1,high);
    }

}

public static void partition(int []data,int low,int high){
    int pivotkey = data[low];
    while(low<high){
        while((low<high)&&(data[high]>=pivotkey))
            high--;
        data[low]=data[high];//减少不必要的交换
        while((low<high)&&(data[low]<=pivotkey))
            low++;
        data[high]=data[low];
    }
    data[low]=pivotkey;
    return low;
}

注意:如果数组比较小,利用直接插入排序的效率要比快排的效率高;
优化代码二(优化递归,对Qsort实时尾递归):

public static void Qsort(int []data,int low ,int high){

    int pivot;
    if((high-low)>MAX_LENGTH_INSERT_SORT){
        while(low<high){
            pivot = partition(data,low,high);
            Qsort(data,low,pivot-1);//对低子表递归排序
            low=pivot+1; //尾递归
        }
    }
    else
        InsertSort(data);//数组较小时采用插入排序
}

其中,将if改成while,并且,更新low,而且只递归低子表。采用迭代的方式,减小堆栈的深度,从而提高性能。

优化三:
快排的非递归实现,利用数组模拟栈来存储子数组的左右边界:

void quicksort_unrecursion(vector<int>&arr)//快速排序非递归  
 {  
     int mystack[2000];//假设递归不超过1000层  
     //栈中保存下次需要排序的子数组的开始位置和结束位置  
     int top = -1;  
     mystack[++top] = 0;  
     mystack[++top] = arr.size() - 1;  
     while(top > 0)//栈非空  
     {  
         int high = mystack[top--], low = mystack[top--];  
         int middle = mypartition(arr, low, high);  
         if(middle+1 < high)//右边子数组入栈  
         {  
             mystack[++top] = middle+1;  
             mystack[++top] = high;  
         }  
         if(low < middle-1)//左边子数组入栈  
         {  
             mystack[++top] = low;  
             mystack[++top] = middle-1;  
         }  
     }  
 }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值