迭代和递归的区别———以快速排序算法为例

https://www.cnblogs.com/surgewong/p/3381438.html

这是一篇讲解快速排序算法的文章

排序算法简介

排序算法有很多种,例如冒泡排序法,堆排序法,简单排序法以及快速排序法等。其中,快速排序算法的时间复杂度为o(nlogn),冒泡排序算法的时间复杂度为o(n^2).故快速排序算法比较快,但是其不稳定。

稳定性是指:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

快速排序法

快速排序算法的核心就是,先找到一个值A,把待排序的数据中小于A的放在A数据的左边,大于的放在A的右边。对A左边的数据与右边的数据分别再进行上述的操作,直到数据达到稳定的效果。

这显然是一个递归的算法。详细描述如下:

详细描述:首先在要排序的序列 a 中选取一个中轴值,而后将序列分成两个部分,其中左边的部分 b 中的元素均小于或者等于 中轴值,右边的部分 c 的元素 均大于或者等于中轴值,而后通过递归调用快速排序的过程分别对两个部分进行排序,最后将两部分产生的结果合并即可得到最后的排序序列。

  “基准值”的选择有很多种方法。最简单的是使用第一个记录的关键字值。但是如果输入的数组是正序或者逆序的,就会将所有的记录分到“基准值”的一边。较好的方法是随机选取“基准值”,这样可以减少原始输入对排序造成的影响。但是随机选取“基准值”的开销大。

  为了实现一次划分,我们可以从数组(假定数据是存在数组中)的两端移动下标,必要时交换记录,直到数组两端的下标相遇为止。为此,我们附设两个指针(下角标)i 和 j, 通过 j 从当前序列的有段向左扫描,越过不小于基准值的记录。当遇到小于基准值的记录时,扫描停止。通过 i 从当前序列的左端向右扫描,越过小于基准值的记录。当遇到不小于基准值的记录时,扫描停止。交换两个方向扫描停止的记录 a[j] 与 a[i]。 然后,继续扫描,直至 i 与 j 相遇为止。扫描和交换的过程结束。这是 i 左边的记录的关键字值都小于基准值,右边的记录的关键字值都不小于基准值。

  通过两个不相邻元素交换,可以一次交换消除多个逆序,加快排序速度。快速排序方法在要排序的数据已经有序的情况下最不利于发挥其长处。

 

  下面我们通过一个案例来演示一下快速排序的基本步骤: 以序列 46 30 82 90 56 17 95 15   共8个元素

    初始状态:     46  30  82  90  56  17  95  15        选择46 作为基准值,i = 0, j = 7

           i = 0                                j = 7

                   15  30  82  90  56  17  95  46       15 < 46, 交换 15 和 46,移动 i, i = 1

             i = 1                           j = 7

            15  30  82  90  56  17  95  46       30 < 46, 不需要交换,移动 i , i = 2

               i = 2                   j = 7

            15  30  46  90  56  17  95  82       82 > 46, 交换82 和 46,移动 j , j = 6

               i = 2               j = 6

            15  30  46  90  56  17  95  82       95 > 46, 不需要交换,移动 j , j = 5

               i = 2         j = 5

            15  30  17  90  56  46  95  82       17 < 46, 交换46 和 17,移动 i, i = 3

                 i = 3    j = 5

            15  30  17  46  56  90  95  82       90 > 46, 交换90 和 46,移动 j , j = 4

               3 = i    j = 4

            15  30  17  46  56  90  95  82       56 > 46, 不需要交换,移动 j , j = 3

                     i  =  j = 3

    

    i = j = 3, 这样序列就这样分割成了两部分,左边部分{15, 30, 17} 均小于 基准值(46);右边部分 {56, 90,95,82},均大于基准值。这样子我们就达到了分割序列的目标。在接着对子序列用同样的办法进行分割,直至子序列不超过一个元素,那么排序结束,整个序列处于有序状态。

python代码如下

import numpy as np
import time

start=time.clock()

def gatedata(filename):
    fr=open(filename)
    arraylines=fr.readlines()
    longoflines=len(arraylines)
    index = 0
    returnmat=np.zeros((longoflines,1),dtype="float_")
    for lines in arraylines:
        line = lines.strip()
        lines=line.split()
        returnmat[index,0]=lines[1]
        index+=1
    return returnmat

a=gatedata("D:\\python进阶\\birch\\data1.txt")

class SQList:
    def __init__(self, lis=None):
        self.r = lis

    def swap(self, i, j):
        """定义一个交换元素的方法,方便后面调用。"""
        self.r[[i,j],:]=self.r[[j,i],:]

    def quick_sort(self):
        """调用入口"""
        self.qsort(0, self.r.shape[0]-1)

    def qsort(self, low, high):
        """递归调用"""
        if low < high:
            pivot = self.partition(low, high)
            self.qsort(low, pivot-1)
            self.qsort(pivot+1, high)

    def partition(self, low, high):
        """
        快速排序的核心代码。
        其实就是将选取的pivot_key不断交换,将比它小的换到左边,将比它大的换到右边。
        它自己也在交换中不断变换自己的位置,直到完成所有的交换为止。
        但在函数调用的过程中,pivot_key的值始终不变。
        :param low:左边界下标
        :param high:右边界下标
        :return:分完左右区后pivot_key所在位置的下标
        """
        lis = self.r
        pivot_key = lis[low,0]
        while low < high:
            while low < high and lis[high,0] >= pivot_key:
                high -= 1
            self.swap(low, high)
            while low < high and lis[low,0] <= pivot_key:
                low += 1
            self.swap(low, high)
        return low

    # def __str__(self):
    #     ret = ""
    #     for i in self.r:
    #         ret += " %s" % i
    #     return ret

if __name__ == '__main__':
    sqlist = SQList(a)
    sqlist.quick_sort()
end=time.clock()
#print(sqlist.r)
print('The program consums %f seconds'%(end-start))

 

 

你可能感兴趣的:(迭代和递归的区别———以快速排序算法为例)