【程序员笔试面试必会——排序①】Python实现 冒泡排序、选择排序、插入排序、归并排序、快速排序、堆排序、希尔排序

最近在准备笔试题和面试题,把学到的东西整理出来,一来是给自己留个笔记,二来是帮助大家学习。

 

题目:

给定一个int数组A及数组的大小n,请返回排序后的数组。  

测试样例: 
输入:[1,2,3,5,2,3],6
返回:[1,2,2,3,3,5]

代码示例:

冒泡排序:O(n^2)

  最基本的排序,不多解释。

class BubbleSort:
    def bubbleSort(self, A, n):
        for x in xrange(n):
            for y in xrange(n-x-1):
                if A[y] > A[y+1]:
                    A[y], A[y+1] = A[y+1], A[y]
        return A

选择排序:O(n^2)

  想象成每次从一大堆数里面选出最小的数放在左边,重复直到这一大对数都被选完。

class SelectionSort:
    def selectionSort(self, A, n):
        for i in xrange(n-1):
            min_index = i
            for j in xrange(i+1, n):
                if A[min_index] > A[j]:
                    min_index = j
            if min_index != i:
                A[i], A[min_index] = A[min_index], A[i]
        return A

插入排序:O(n^2)

  想象成打麻将时,摸到一个排插入到已有的麻将里边。选择排序从左边第二个牌开始,与左边的牌比较,如果比左边的小就与其交换位置,依次重复此步骤,直到排序完所有的牌。

class InsertionSort:
    def insertionSort(self, A, n):
        for i in xrange(1, n):
            tmp = A[i]
            j = i - 1
            while tmp < A[j] and j >= 0:
                A[j+1] =  A[j]
                j -= 1
            A[j+1] = tmp
        return A

归并排序:O(n*log n)

  分治法思想。把所有的数看成长度为1的有序区间:[1],[2],[3],[5],[2],[3],再将相邻的区间合并成为最大长度为2的有序区间:[1,2],[3,5],[2,3],再合并成为最大长度为4的有序区间:[1,2,3,5],[2,3],再合并:[1,2,2,3,3,5]。 

class MergeSort:
    def mergeSort(self, A, n):
        if n <= 1:
            return A
        half = n / 2
        left = self.mergeSort(A[:half], half)
        right = self.mergeSort(A[half:], n-half)
        
        result = []
        i = j = 0
        while i < len(left) and j < len(right):
            if left[i] < right[j]:
                result.append(left[i])
                i += 1
            else:
                result.append(right[j])
                j += 1
        result += left[i:]
        result += right[j:]

        return result

快速排序:O(n*log n)

  从这些数中随意选一个数,小于这个数的放在它左边,大于它的放右边;再在这左右两边的一堆数重复使用这个方法,直到排序结束。

class QuickSort:
    def quickSort(self, A, n=None):
        if not A:
            return []
        else:
            key = A[0]  # 固定每次选择最左边的数
            left = self.quickSort([n for n in A[1:] if n <= key])
            right = self.quickSort([n for n in A[1:] if n > key])
            return left + [key] + right

 堆排序:

  在这里我们借用wiki的定义来说明: 通常堆是通过一维数组来实现的,在阵列起始位置为0的情况中 

    (1)父节点i的左子节点在位置(2*i+1); 
    (2)父节点i的右子节点在位置(2*i+2); 
    (3)子节点i的父节点在位置floor((i-1)/2);

# -*- coding:utf-8 -*-

class HeapSort:
    def heapSort(self, A, n):
        # 创建大根堆
        for i in xrange(n/2 + 1, -1, -1): 
            self.max_heap_fix(A, i, n)
        # 堆排序
        for i in xrange(n-1, -1, -1):
            A[0], A[i] = A[i], A[0]
            self.max_heap_fix(A, 0, i)
        return A

    def max_heap_fix(self, A, i, n):
        """
        :param A: 大根堆、一维数组
        :param i: 预修复的子树根节点
        :param n: 大根堆总的元素数量
        """
        j = i * 2 + 1  # i的左子节点下标
        # 当i的左子节点存在时
        while j < n:
            # 当i的右子节点存在,且大于i的左子节点
            if j + 1 < n and A[j] < A[j+1]:
                j += 1
            # 当i的左右子节点都小于i时,修复大根堆结束
            if A[j] < A[i]:
                break
            # 当i的子节点大于i时,交换节点
            A[i], A[j] = A[j], A[i]
            i = j  # 将i移向于i交换的节点
            j = i * 2 + 1  # i的左子节点下标

希尔排序:

   插入排序是希尔排序的一种特殊情况,当希尔排序的初始步长为1时,即为插入排序。

class ShellSort:
    def shellSort(self, A, n):
        step = n / 2
        while step > 0:
            for i in xrange(step, n):
                tmp = A[i]
                while i >= step and tmp < A[i-step]:
                    A[i] = A[i-step]
                    i -= step
                A[i] = tmp
            step = step / 2
        return A

 

posted @ 2018-01-12 15:13  WangC.W  阅读(638)  评论(0编辑  收藏  举报