常见的排序

一,冒泡排序算法

        1.冒泡排序的规则

           冒泡排序是我们最常见的排序方式,就是将相邻的两个元素进行比较,如果前一个比后面的元素大,就将其调换位置。重复上面的动作,最后一个不进行比较,直到没有数据进行比较。

           最差时间复杂度:O(n^2)

           平均时间复杂度:O(n^2)

           最优时间复杂度:如果能再内部循环第一次运行时,使用一个旗标来表示有无需要交换的可能,可以把最优时间复杂度降低到O(n)

           稳定性:稳定

        2.代码实现

            public void swap(int A[],int i,int j)

            {

                        int temp=A[i];

                        A[i]=A[j];

                        A[j]=temp;

            }

            public BubbleSort(int A[],int n)//A是带入的数组,n是数组长度

            {

                        for(int j=0;j<n-1;j++)    //每次最大元素就像气泡浮到数组的最后

                        {

                               for(int i=0;i<n-1-j;i++)//依次比较相邻的两个元素,使较大的那个向后移动

                               {

                                    if(a[i]>a[i+1])

                                    {

                                          swap(A,i,i+1)

                                     }

                               }

                        }

             }


       


           使用冒泡排序为一列数字进行排序的过程如上图所示。

           冒泡排序是很好了解的也是很容易实现的,但是对于少量数据进行排序之外,是相当没有效率的。

二,鸡尾酒排序(冒泡排序的改进)

           鸡尾酒排序也叫定向冒泡排序,此算法与冒泡排序的不同处在于从低到高然后从高到低,而冒泡排序的则从低到高比较有序列的去比较数组中的每个元素。

           1.代码实现

                    

           public void swap(int A[],int i,int j)

            {

                        int temp=A[i];

                        A[i]=A[j];

                        A[j]=temp;

            }

            public void CocktailSort(int a[],int n)
{
int left=0;//初始化边界
int right=n-1;
while(left<right)
{
for(int i=left;i<right;i++)//前半程,将最大的数字往后面放
{
if(A[i]>A[i+1])
{
swap(A,i,i+1);
}
}
right--;
for(int i=right;i>left;i--)
{
if(A[i-1]>A[i])
{
swap(A,i,i+1);
}
}
left++
}
}

比较,已序列(2,3,4,5,1)为例  ,鸡尾酒排序只需要一次就能完成排序,而冒泡就需要进行四次排序,但是在乱数的序列的状态下,鸡尾酒与冒泡排序的效率都很差劲的。

三,选择排序

       1.选择排序的规则

          选择排序也是一种简单直观的排序算法,工作原理就是初始时在序列找到最小(大)的元素,房贷续流的起始位置,无限次的循环下去,直到循环完成。、

         注意: 选择排序与冒泡排序的区别:冒泡排序通过依次交换,相邻两个顺序不合法的元素位置,从而将当前最小(大)元素放到合适的位置。而选择排序每遍历一次都记住当前最小(大)元素的位置,最后仅需一次交换操作,即可将其放到合适的位置去。

           最差时间复杂度:O(n^2)

           平均时间复杂度:O(n^2)

           最优时间复杂度:O(n^2)

           稳定性:不稳定


       2.代码实现

   

 public void swap(int A[],int i,int j)

            {

                        int temp=A[i];

                        A[i]=A[j];

                        A[j]=temp;

            }

public void SelectionSort(int A[],int n)
{
for(int i=0;i<n-1;i++)//i为已排序序列的末尾
{
int min=i;
for(int j=i+1;j<n;j++)//未排序序列
{
if(A[j]<A[min])//找出未排序的序列中的最小值
{
min=j;
}
}
if(min!=i)
{
swap(A,min,i);//放到已排序的末尾,该操作很有可能把稳定性打乱,所以选择排序是不稳定的排序算法
}
}
}


四,插入排序

       1.插入排序的规则

          插入排序是一种简单直观的排序算法,工作原理类似于我们抓扑克牌

         从第一个元素开始,该元素可以认为已经被排序

         取出下一个元素,在已经排序的元素序列中从后向前扫描

         如果该元素(已排序)大于新元素,将元素移动到下一位置

        重复上述步骤,知道找到已排序的元素小于或等于新元素的位置

        将元素插入到该位置

           最差时间复杂度:O(n^2)

           平均时间复杂度:O(n^2)

           最优时间复杂度:O(n)

           稳定性:稳定

       2.代码实现
public void InsertionSort(int A[],int n)
{
for(int i=1;i<n;i++)  //类似抓扑克牌排序
{
int get=A[i]//右手抓到一张扑克牌   
int j=i-1;//拿在左手上的牌总是排序好的
while(j>=0&&A[j]>get)//将抓到的牌与手上的牌进行比较
{
A[j+1]=A[j];//如果该手牌比抓到的牌大就将其右移
j--;
}
A[j+1]=get;//直到该手牌比抓到的牌小(或二者相等),将抓到的牌插入到最右边
}
}


插入排序不适合对于数据量比较大的应用。在STL的sort算法和stdlib的qsort算法中,都将插入排序作为快速排序的补充。

   五,二分插入排序

      对于插入排序,如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的次数,称之为二分插入排序

     

          最差时间复杂度:O(n^2)

           平均时间复杂度:O(n^2)

           最优时间复杂度:O(nlogn)

           稳定性:稳定

    代码实现:

            public void InsertionSortDichotoomy(int A[],int n)
{
for(int i=1;i<n;i++)
{
int get=A[i];           //右手拿到一张扑克牌
int left =0;             //拿在左手上的牌总是排序好的,所以可以用二分法

int right=i-1;        //手牌左右界进行初始化
while(left<=right)      //采用二分法定位新牌的位置
{
int mid=(left+right)/2;
if(A[mid]>get)
right=mid-1;
else
left=mid-1;
}
for(int j=i-1;j>=left;j--)//将欲插入新牌的右边整体想右移动一个位置
{
A[j+1]=A[j];
}
A[left]=get;    //将抓到的牌插入手牌
}
}

           当n较大时,二分插入排序的比较此时比直接插入的排序的最差情况要好。

六,快速排序

       在平均状况下,排序n个元素要O(nlogn)次比较,在最坏状况下则需要O(n^2)次比较,单这种状况不常见,

      1.快速排序规则

          从序列中挑出一个元素,作为基准

          把所有比基准小的元素放在基准前面,所有比基准大的元素放在基准的后面

         对每个分区在进行上面的操作,递归的结束条件是序列的小小是0或1,这是整体已经被排序好了

     

           最差时间复杂度:O(n^2)

           平均时间复杂度:O(nlogn)

           最优时间复杂度:O(nlogn)

           稳定性:不稳定

         2.代码实现

          

 public void swap(int A[],int i,int j)

            {

                        int temp=A[i];

                        A[i]=A[j];

                        A[j]=temp;

            }

int Partition(int A[],int left ,int right )  //划分函数
{
int pivot=A[right];   //这里每次都选择最后一个元素作为基准
int tail=left-1;      //tail为最小基准的子数索引
for(int i=left;i<right;i++)//遍历基准以外的其他元素
{
if(A[i]<=pivot)   //把小于等于元素放到前一个子数组的末尾
{
swap(A,++tail,i);
}
}
swap(A,tail+1,right);  //最后把基准放到前一个子数组的后边,剩下的子数组既是大于基准的子数组
                      //该操作很有可能把后面的稳定性打乱,所以快速排序不是稳定的算法
return tail+1;         //返回基准索引
}
void QuickSort(int A[],int left,int right)
{
if(left>==right)
return;
int pivot=Partition(A,left,right);
QuickSort(A,left,pivot-1);
QuickSort(A,pivot+1,right);
}

Java系统提供的Arrays.sort函数。对于基础类型,地城使用快速排序,对于非基础类型,底层使用的是归并排序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值