Exemple #1
0
    def pop(self):
        # 弹出最大元素,同时交换最后一个元素和最大元素在维护最大堆
        tool.swap(len(self), 1, self.heap)
        result = self.heap.pop()

        self._shift_down()
        return result
Exemple #2
0
    def __init__(self, arr: []):
        self.heap = arr

        i = len(self.heap) - 1 >> 1
        while i >= 0:
            self._shift_down(i, len(self.heap))
            i -= 1

        for j in range(len(self.heap) - 1, 0, -1):
            tool.swap(0, j, arr)
            self._shift_down(0, j)
Exemple #3
0
 def _shift_up(self, k):
     """
     比较大的数据上浮
         查看父节点是否大于当前节点,如果大交换位置,同时再次检查
     :param k:
     :return:
     """
     parent = self._get_parent(k)
     while k > 1 and self.heap[parent] < self.heap[k]:
         tool.swap(parent, k, self.heap)
         k = parent
         parent = self._get_parent(parent)
Exemple #4
0
    def _shift_down(self, k=1):
        """
        比较小的数据下沉
            从子节点找到最大的数据,使其和父节点交换位置,重复这个操作到,最后元素
        :param k:
        :return:
        """
        while self._get_left_child(k) <= len(self):
            j = self._get_left_child(k)  # 默认使用左节点交换位置
            if j + 1 <= len(self) and self.heap[j + 1] > self.heap[j]:
                # 如果有右节点并且右节点的值大于左节点的值,使用右节点交换
                j += 1

            if self.heap[k] >= self.heap[j]:
                break

            tool.swap(k, j, self.heap)
            k = j
Exemple #5
0
    def bubble_sort(cls, arr: []) -> []:
        """
        冒泡排序:
            找到最大的,排到最后,n次循环这样的过程,最终排好
        :param arr:
        :return:
        """
        length = len(arr)

        for i in range(length):

            max_index = 0
            for j in range(0, length - i):
                if arr[j] > arr[max_index]:
                    max_index = j
                    # arr[j], arr[j + 1] = arr[j + 1], arr[j]

            tool.swap(length - i - 1, max_index, arr)

        return arr
Exemple #6
0
    def shell_sort(cls, arr: []) -> []:
        """
        希尔排序:
            使用偏移量,每次比较几个子序列,用插入排序把数据排好
        :param arr:
        :return:
        """
        offset = len(arr)

        while offset > 1:
            offset = offset // 2

            for i in range(offset, len(arr)):
                # 插入排序
                j = i - offset
                while j >= 0 and arr[j] > arr[j + offset]:
                    tool.swap(j, j + offset, arr)
                    j -= offset

        return arr
Exemple #7
0
    def select_sort(cls, arr: []) -> []:
        """
        选择排序:
            遍历列表,找到列表当前位置到最后位置的最小数,把这个最小数和当前值互换
        :return: []
        """
        assert arr, "not arr"
        length = len(arr)

        for i in range(length):
            min_index = i  # 最小下标

            for j in range(i, length):
                # [i:length] 找到最小数的下标
                if arr[min_index] > arr[j]:
                    min_index = j

            # 位置互换
            tool.swap(i, min_index, arr)

        return arr
Exemple #8
0
    def __partition(cls, arr, l, r):
        """
        使当前[l:r]区间的数组,以第一个数v分割,左边比v小,右边比v大
        :param arr:
        :param l:
        :param r:
        :return: 分割数组的中间下标
        """
        # p = l  # 分割数组的下标
        # tool.swap(random.randint(l, r), l, arr)  # 避免数组基本上是有序的
        # v = arr[l]
        #
        # for i in range(l + 1, r + 1):
        #     if arr[i] < v:
        #         # 如果p下标之后的元素比分割数组的元素v小,则把当前元素和p下标所在位置交换
        #         p += 1
        #         tool.swap(i, p, arr)
        #
        # tool.swap(l, p, arr)
        # return p
        # ============= 处理数组里有大量重复元素
        p = r  # 分割数组的下标
        tool.swap(random.randint(l, r), l, arr)  # 避免数组基本上是有序的
        v = arr[l]
        i = l + 1
        while 1:
            while i <= r and arr[i] < v: i += 1  # 从左边开始,如果当前元素小于中间元素,位置不变,左值加一
            while p > l and arr[p] > v: p -= 1  # 从右边开始,如果当前元素大于中间元素,位置不变,右值减一
            if i > p: break  # 左边和右边已经分开
            tool.swap(i, p, arr)  # 大值放在右边,小值放在左边,无序的
            i += 1  # 完成一次,左值加一,右值减一
            p -= 1

        tool.swap(l, p, arr)  #
        return p
Exemple #9
0
def partition(arr, l, r):
    """
    以v分割数组, 左边的比v小, 右边的比v大
    :param arr:
    :param l:
    :param r:
    :return:
    """
    p = r
    n = random.randint(l, r)
    tool.swap(l, n, arr)
    v = arr[l]
    i = l + 1

    while 1:
        while i <= r and arr[i] < v:
            i += 1
        while p > l and arr[p] > v:
            p -= 1
        if i > p:
            break
        tool.swap(i, p, arr)
        i += 1
        p -= 1

    tool.swap(l, p, arr)

    return p
Exemple #10
0
    def __partition3_ways(cls, arr, l, r):
        tool.swap(random.randint(l, r), l, arr)  # 避免数组基本上是有序的
        v = arr[l]

        lt = l  # [l:lt] < v
        gt = r + 1  # [gt: r] > v
        i = l + 1  # 处理过的下标
        while i < gt:
            if arr[i] < v:
                # 如果当前位小于v,把当前位和第二个元素交换
                tool.swap(i, lt + 1, arr)
                i += 1
                lt += 1
            elif arr[i] > v:
                # 如果当前位大于v,把当前位和最后一个元素交换
                tool.swap(i, gt - 1, arr)
                gt -= 1
            else:
                i += 1

        tool.swap(l, lt, arr)  # 把第一个位置的元素与最后一个小于v的元素交换
        return lt, gt