ALearning(一):排序算法

排序基础知识:

排序:通过元素记录之间的比较,使一个序列中无序的元素变为有序的操作;

排序的稳定性:对于一个待排序的序列,其中两个或以上的相同元素,经过排序后,其相对位置不发生改变的操作称为稳定排序,相应的排序算法,称为稳定的排序算法;相反,如果序列中相同元素排序前后相对位置发生变化,则是不稳定排序;

排序算法的分类:依据是否对外存储器的访问,分为内部排序,外部排序;依据排序原则分为5类:插入排序、交换排序、选择排序、归并排序和基数排序;根据排序过程的时间复杂度来分,可以分为三类:简单排序、先进排序、基数排序。(参见百度百科)

复杂度知识:https://blog.csdn.net/yushiyi6453/article/details/76407640

一、插入排序

插入排序:将一个元素插入到一个已排序序列中的方法;实际比较次数n(n-1)/2,移动次数(n+4)(n-2)/2;

当对一个长度为n的无序序列进行排序时(索引从0开始),有以下步骤:

                 一、已排序序列初始为仅包括索引为0的元素的序列,由于仅存在一个元素,所以该序列必然是“有序的”;

                 二、若已排序序列长度为m(最大索引为m-1),将索引为m的元素降索引逐元素与已排序序列元素比较,直至存在元素                 (索引为k,k<m)小于该元素,或索引降至k=-1,同时将索引大于k的元素逐位后移,将索引为m的元素插入到索引k+1 处;

                 三、索引为m元素插入已排序序列,已排序序列长度加1(m+1),不断重复步骤二,直至无未插入元素;

python代码如下:

class SQAlogrithm(object):
    
    def __init__(self,seq):
        
        self._list=seq
        self.num=0
        
    def Insert_sort(self):
        """
        直接插入排序,O(n^2),实际比较次数n(n-1)/2,移动次数(n+4)(n-2)/2;
        将一个元素插入已排序序列中;
        """
        length=len(self._list)
        
        for i  in range(1,length):
            
            if self._list[i]<self._list[i-1]:
                
                insert_value=self._list[i]
                self._list[i]=self._list[i-1]
                j=i-1
                while j>0 and self._list[j]>insert_value:
                    self._list[j+1]=self._list[j]
                    j-=1
                
                self._list[j+1]=insert_value

二、希尔排序

       希尔排序是插入排序的改进,通过设置一个增量increment,将待排序序列分成increment个子序列,在每个子序列中应用插入排序,随着增量的逐渐减少,每个子序列的元素逐渐增多,当增量为1时,即是对整个序列进行插入排序,但由于前面的子序列排序,此时的序列已经是个相对有序的无序序列,因此即使此处与直接插入排序相似,但极大地减少了移动元素的开销,使其一般地相对直接插入排序更为高效。由于希尔排序进行了多次排序,相同的元素可能会在不同的排序过程中发生移动,因此是一种不稳定排序方法。

       希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n²),而Hibbard增量的希尔排序的时间复杂度为O(  ),希尔排序时间复杂度的下界是n*log2n。希尔排序没有快速排序算法快 O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择,但是比O(  )复杂度的算法快得多。(参见百度百科)

希尔排序是基于插入排序的以下两点性质而提出改进方法的:(参见百度百科)

  1. 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。

  2. 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。

对于一个长度为n的无序序列,其希尔排序步骤如下:

      一、确定增量increment;

      二、遍历的按增量进行插入排序(遍历范围:range(increment~n,1))

      三、减小增量,重复步骤二,当增量减小至1时,对整个序列进行插入排序,排序完毕;

python代码如下:

def Shell_sort(self):
        """
        希尔排序,插入排序的改进,又叫缩小增量排序;
        """
        length=len(self._list)    
        increment=length
        
        while increment !=1:
            increment=int(increment/3)+1
            for i in range(increment,length):
                if self._list[i]<self._list[i-increment]:
                    temp=self._list[i]
                    j=i-increment
                    while j>=0 and temp<self._list[j]:
                        self._list[j+increment]=self._list[j]
                        j=j-increment
                    self._list[j+increment]=temp
                    

三、冒泡排序

       对一个长度为n的无序序列的相邻元素间进行比较,若正序则位置不变,若反序,则交换位置;

       冒泡排序有两种实现方式,第一种,从第一个元素开始比较,一轮比较完毕后,最大的元素位于序列最后;第二种,从最后一个元素开始比较,一轮比较完毕后,最小元素位于序列最前;

       由于冒泡排序的比较和交换操作均发生在相邻元素之间,元素相同则不发生交换,因此冒泡排序是稳定排序算法。最好情况下,即序列为正序,此时比较次数为n-1,交换次数为0;最坏情况下,即序列为反序的,此时比较次数n(n-1)/2,交换次数

3n(n-1)/2,因此冒泡排序平均时间复杂度为O(n^2)。

第一种实现步骤:

       一、遍历计数 count初始为0,遍历范围range(n);

       二、比较开始索引m,初始为n-1,降索引比较,直至索引等于count,此时count=count+1,m=m-1;

       三、若开始索引m大于遍历计数count,重复步骤二,否则结束排序操作;

python代码如下:

def Bubble_sort(self):
        """
        冒泡排序,O(n^2),实际比较次数n(n-1)/2;
        元素间两两比较,如反序则交换,否则不交换;
        """
        length=len(self._list)
        
        for i in range(length):
            
            j=length-1
            while j>i:
                
                if self._list[j-1]>self._list[j]:
                
                    self._list[j-1]=self._list[j-1]^self._list[j]
                    self._list[j]=self._list[j-1]^self._list[j]
                    self._list[j-1]=self._list[j-1]^self._list[j]
                j-=1

四、快速排序

       冒泡排序的改进,对于一个长度为n的无序序列,首先选择一个分割值split_value,对于该分割值索引之后的子序列,降索引逐元素比较,若存在大于该分割值的元素,则彼此交换位置,同时停止比较;之后对该分割值新位置之前的子序列,升索引逐元素比较,若存在大于该分割值的元素,则彼此交换位置,同时停止比较;这两个过程可以不断递归进行,以达到排序目的。

       最好的情况下时间复杂度为O(nlogn),空间复杂度为O(logn);最差的情况下时间复杂度为O(n^2),空间复杂度为O(n)。

       快速排序步骤:

        一、开始索引start,初始为0,结束索引end,初始为n-1,选择分割值,初始索引为序列第一个元素索引k;

        二、对索引k之后的范围进行降索引比较,开始start=k+1,end=end,直至出现第一个小于该分割值的元素,彼此交换位置,更新end;

        三、对索引k之前的范围进行降索引比较,此时start=start,end=k-1,直至出现第一个大于该分割值的元素,彼此交换位置,更新start;

        四、若start<end,则重复一二三步骤,最终返回分割值索引,结果是分割值左边元素均小于等于分割值,右侧元素均大于等于分割值;

        五、对分割值左右两边子序列不断递归进行上述步骤(不包含分割值),当所有递归过程完成,排序完毕。

python代码:

def Quick_sort(self):
        """
        冒泡排序的改进,
        """
        start=0
        end=len(self._list)-1
        
        def iter_quick_sort(in_start,in_end):
            
            if in_start<in_end:
                
                split_point=Quick_sort_main(in_start,in_end)
                iter_quick_sort(in_start,split_point-1)
                iter_quick_sort(split_point+1,in_end)
            
        def Quick_sort_main(start,end):
            
            while start<end:
                while start<end:
                    if self._list[end]>=self._list[start]:
                        end-=1
                    else:
                        self._list[end]=self._list[end]^self._list[start]
                        self._list[start]=self._list[end]^self._list[start]
                        self._list[end]=self._list[end]^self._list[start]
                        break
                while start<end:
                    if self._list[start]<=self._list[end]:
                        start+=1
                    else:
                        self._list[end]=self._list[end]^self._list[start]
                        self._list[start]=self._list[end]^self._list[start]
                        self._list[end]=self._list[end]^self._list[start]
                        break
            return start
          
        iter_quick_sort(in_start=start,in_end=end)

五、选择排序

对于一个长度为n的无序序列,每一轮从未排序序列中选择最小值与该序列起始位置元素交换;选择排序是不稳定排序。

最好情况下,即序列为正序,此时比较次数为n-1,交换次数为0;最坏情况下,即序列为反序的,此时比较次数n(n-1)/2,交换次数  (n - 1),平均时间复杂度为O(n^2)。

步骤如下:

       一、对于未排序子序列(相对于原始序列,索引范围为:range(m,k)),初始为原始序列,m=0,k=n-1,逐元素比较,选择出最小元素与该未排序子序列起始元素交换,此时m=m+1,k=k;

       二、重复步骤一,直至m=k,排序完毕。

python代码:

def Select_sort(self):
            """
            选择排序:O(n^2),
            对尚未排序的序列部分,进行遍历,依次比较,记录最小值,将该值放到该次遍历序列最前方;
            """           
            length=len(self._list)
            i=0
            
            while i <length:
                
                temp=i
                for j in range(i+1,length):
                    if self._list[j]<self._list[temp]:
                        temp=j
                if i!=temp:
                    self._list[i]=self._list[i]^self._list[temp]
                    self._list[temp]=self._list[i]^self._list[temp]
                    self._list[i]=self._list[i]^self._list[temp]
    
                i+=1             

六、归并排序

        基于分治法的一种排序方法,先使得相邻的子序列内有序,再使得相邻子序列间有序;假设二分的层数从b到g,则

        步骤如下:

          一、对无序序列递归的进行二分;

          二、当序列f1二分的子序列(g层)均为1时,对该序列的两个子序列进行排序,由于此时仅存在两个元素,最多一次比较交换即可;

          三、对与步骤二同一级的序列f2进行步骤二的操作,得到有序的f2;

          四、对f1和f2进行序列间的排序,得到有序序列e1;相同方法得到e1的同级有序序列e2;

          五、不断重复步骤四的操作,直至对初次二分序列b1和b2进行序列间排序,排序完毕;

python代码如下:

def Merge_sort(self):
        
        start=0
        end=len(self._list)
        
        def _split(_list,_start,_end):
            
            if len(_list[_start:_end])==1:
                return
            mid=int(len(_list[_start:_end])/2)+_start
            print(_start,mid,_end)
            _split(_list,_start,mid)
            _split(_list,mid,_end)
            
            union(_list,_start,mid,_end)
            
        def union(_list,start,mid,end):
            
            new=[]
            length_left=len(self._list[start:mid])
            length_right=len(self._list[mid:end])
            i=j=0
            while i<length_left and j<length_right:
                if self._list[start:mid][i]<=self._list[mid:end][j]:
                    new.append(self._list[start:mid][i])
                    i+=1
                else:
                    new.append(self._list[mid:end][j])
                    j+=1
            while i<length_left:
                new.append(self._list[start:mid][i])
                i+=1
            while j<length_right:
                new.append(self._list[mid:end][j])
                j+=1
            self._list[start:end]=new
         
        _split(self._list,start,end)

猜你喜欢

转载自blog.csdn.net/zhuzhongzhuo/article/details/86234100
今日推荐