排序算法整理

在写这篇文章的时候我还是初学者--希望能通过博客观察自己的成长

 

首先声明:算法均参考自  <数据结构教程>--李春葆著

 

所用到的数据结构---这里为简便,使用简单的int值

class ElemType
{
    ElemType(int data)
    {
        this.data=data;
    }
    public int data;
}

main函数

public static void main(String[] args)
    {
        ElemType [] R=new ElemType[10];
        for(int i=0;i<10;i++)
        {
            R[i]=new ElemType((int)(Math.random()*10));
        }
        for(ElemType r:R)
            System.out.print(r.data);
        System.out.println();
        
        quicksort(R,0,9);        //快速排序
        insertSort(R,10);        //直接插入排序
        insertSort2(R,10);        //折半插入排序
        shellSort(R,10);        //希尔排序
        bubbleSort(R,10);        //冒泡排序
        selectSort(R,10);        //直接选择排序

        
        heapSort(R,10);            //堆排序(数据序列的下标从1开始)    
        
        
        for(ElemType r:R)
        System.out.print(r.data);
        
    }

插入排序:      包括直接插入排序,折半插入排序,希尔排序

    static void insertSort(ElemType[]R,int n)//直接插入排序
    {
        int i,j;
        ElemType tmp;
        for(i=1;i<n;i++)
        {
            tmp=R[i];
            j=i-1;          //从右向左在有序区R[0...i-1]中找R[i]的位置
            while(j>=0&&R[j].data>tmp.data)//当不成立的时候,j即需要插入的元素的位置
            {
                R[j+1]=R[j];//将关键字大于R[i].data的元素后移
                j--;
            }
            R[j+1]=tmp;     //在J+1处插入R[i];
        }
    }
    static void insertSort2(ElemType[] R, int n)//折半插入排序
    {
        int i, j, low, high, mid;
        ElemType tmp;
        for (i = 1; i < n; i++)
        {
            tmp = R[i];                     //将R[i]保存到tmp中
            low = 0;
            high = i - 1;
            while (low <= high)             //在R[low...high]中折半查找有序插入的位置
            {
                mid = (low + high) / 2;     //取中间位置
                if (tmp.data < R[mid].data)
                    high = mid - 1;         //插入点在左半区
                else
                    low = mid + 1;          //插入点右半区
            }
            for(j=i-1;j>=high+1;j--)        //元素后移
                R[j+1]=R[j];
                R[high+1]=tmp;              //插入
            
        }
        
    }
    static void shellSort(ElemType[] R,int n)  //希尔排序
    {
        int i,j,gap;
        ElemType tmp;
        gap=n/2;                                //增量置初值
        while(gap>0)
        {
            for(i=gap;i<n;i++)                  //对所有相隔gap位置的元素组采用直接插入排序
            {
                tmp=R[i];
                j=i-gap;
                while(j>=0&&tmp.data<R[j].data) //对相隔gap位置的元素组进行排序
                {
                    R[j+gap]=R[j];
                    j=j-gap;
                }
                R[j+gap]=tmp;
            }
            gap=gap/2;                          //减少增量
        }
    }

 

交换排序:   包括冒泡排序和快速排序

 

    static void bubbleSort(ElemType []R ,int n)//冒泡排序
    {
        
        int i,j;
        ElemType tmp;
        for(i=0;i<n-1;i++)
        {
            boolean flag=false;     //改进
            for(j=n-1;j>i;j--)          //逐个比较,依次将无序区中最小元素移动到有序区的队首
            if(R[j].data<R[j-1].data)
            {
                tmp=R[j];
                R[j]=R[j-1];
                R[j-1]=tmp;
                flag=true;
            }
            if(!flag)
                return;             //本次没有发生交换--提前结束排序
        }
    }

 

    static void quicksort(ElemType[] R,int s,int t)//快速排序(s,t分别是头尾)
    {
        int i=s,j=t;    //i,j分别将头尾保存起来
        ElemType tmp;   //用于比较,传值
        if(s<t)         //可以理解为  s!=t
        {
            tmp=R[s];   //将头保存起来,其实这个是作为参照值,可以任选 为方便 将头作为参照对象
            while(i!=j) //i!=j的时候意味着没有遍历完成(目的要将范围内小的放左边,大的放右边   i==j的时候 i即中间值)
            {
                while(j>i&&R[j].data>=tmp.data)//j向右遍历,直到i==j或者出现了tmp>R[j]的情况--执行交换操作
                j--;
                
                R[i]=R[j];            //找到一个小于tmp.data的R[j]-- R[i]跟R[j]交换(假如R[i]=)
                while(i<j&&R[i].data<=tmp.data)//i向左遍历,直到i==j或者出现了tmp<R[i]的情况--执行交换操作
                    i++;
                
                R[j]=R[i];
            }
            R[i]=tmp;
            quicksort(R,s,i-1);
            quicksort(R,i+1,t);        //i为中间值,所以只需要将i左边和i右边的处理即可
        }

    }

 

选择排序: 包括直接选择排序和堆排序

    static void selectSort(ElemType[]R ,int n)//直接选择排序
    {
        int i,j,k;
        ElemType tmp;
        for(i=0;i<n-1;i++)              //做第i趟排序
        {
            k=i;
            for(j=i+1;j<n;j++)          //在当前无序区R[i...n-1]中选择key最小的R[k]    
                if(R[j].data<R[k].data)
                    k=j;                //k记下目前找到的最小关键字所在的位置
            if(k!=j)                    //交换R[i]和R[k]
            {
                tmp=R[i];
                R[i]=R[k];
                R[k]=tmp;
            }
        }
    }

 

//堆排序    
    static void sift(ElemType []R ,int low, int high)//调整堆
    {
        int i=low,j=2*i;                        //R[j]是R[i]的左孩子
        ElemType tmp=R[i];
        while(j<=high)
        {
            if(j<high&&R[j].data<R[j+1].data)   //若有孩子较大,把j指向右孩子
                j++;
            if(tmp.data<R[j].data)
            {
                R[i]=R[j];                      //将R[j]调整到双亲节点位置上
                i=j;                            //修改i和j值,以便继续向下筛选
                j=2*i;
            }
            else break;                         //筛选结束
        }
        R[i]=tmp;                               //被筛选节点的值放入最终位置
    }
    static void heapSort(ElemType[] R,int n)//堆排序(注意,为了与二叉树的顺序结构存储一致,堆排序的数据序列的下标从1开始)
    {
        int i;
        ElemType tmp;
        for(i=n/2;i>=1;i--)     //循环建立初始堆
            sift(R,i,n);
            
        for(i=n;i>=2;i--)       //进行n-1躺堆排序,每一趟堆排序的元素个数减一
        {
            tmp=R[1];           //将最后一个元素同当前区间内R[1]对换
            R[1]=R[i];          
            R[i]=tmp;
            sift(R,1,i-1);      //筛选R[1]节点,得到i-1个节点的堆
        }
    }    
    
}

这里要注意一下,由于堆排序的数据序列下标从1开始,因此数据格式跟其他排序不一样

这里贴出一个专门用于堆排序测试的main函数

    public static void main(String[] args)
    {
        ElemType [] R=new ElemType[11];
        R[0]=new ElemType(-1);
        for(int i=1;i<11;i++)
        {
            R[i]=new ElemType((int)(Math.random()*10));
        }
        for(int i=1;i<11;i++)
            System.out.print(R[i].data); 
        System.out.println();
        
        heapSort(R,10);
        
        for(int i=1;i<11;i++)
        System.out.print(R[i].data);  
    }

 

归并排序:

public static void mergeSort(ElemType R[],int n)//自底向上的二路归并算法
    {
        int length;
        for(length=1;length<n;length=2*length)      //进行Log(n)趟归并
            MergePass(R,length,n);
        
    }
    public static void MergePass(ElemType[]R,int length,int n)//对整个表进行一趟归并
    {
        int i;
        for(i=0;(i+2*length-1)<n;i=i+2*length)  //归并length长的两相邻子表
           Merge(R,i,i+length-1,i+2*length-1);
        if(i+length-1<n)                        //余下两个子表,后者长度小于length
            Merge(R,i,i+length-1,n-1);          //归并这两个子表
    }
    public static void Merge(ElemType R[],int low ,int mid ,int high)
    {
        ElemType[] Rt=new ElemType[R.length];
        int i=low,j=mid+1,k=0;      //k是R1的下标,i,j分别是第1,2段的下标
        while(i<=mid&&j<=high)      //在第一第二段均未扫描完成时循环
        if(R[i].data<=R[j].data)    //将第一段中的元素放入R1中
        {
            Rt[k]=R[i];
            i++;k++;
        }
        else{                       //将第二段中的元素放入R1中
            Rt[k]=R[j];
            j++;k++;
        }
        while(i<=mid)               //将第一段余下部分复制到R1中
        {
            Rt[k]=R[i];
            i++;k++;
        }
        while(j<=high)              //将第二段余下部分复制到R1中
        {
            Rt[k]=R[j];
            j++;k++;
        }
        for(k=0,i=low;i<=high;k++,i++)//将R1复制回R中
            R[i]=Rt[k];
        
    }

 

posted @ 2017-04-11 13:16  右丶羽  阅读(246)  评论(0编辑  收藏  举报