原地排序 or 新空间排序?

文章介绍了如何对已排序的列表进行分散排序,提供了两种方法:原地排序使用双指针策略,新空间排序通过开辟额外空间。原地排序节省空间但可读性较低,新空间排序则提高了可读性,但增加了空间复杂度。在实际应用中,可根据需求权衡选择。
摘要由CSDN通过智能技术生成

 1、问题描述

        将升序排列后的元素重新分布,使相同元素分割排列,例如原始数组列表为:

[5, 2, 2, 1, 4, 3, 5, 5, 1, 2, 4]

        升序排列后的结果为:

[1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5]

        分散排列后的结果为:

[2, 5, 1, 2, 4, 5, 1, 2, 3, 4, 5]

2、原地排序

2.1 提取关键处理

 双指针

    steps01    P1:找到第一个重复数据的位置

    steps02    P2:找到第一个与P1位置数据不同,且小于P1右边数据的位置

    steps03    [P2 + 1, P1] 区间内的数据左移1位,并将P2位置的数据移到P1的位置

    steps04    将P1更新为原P1左边的第一个位置,重复步骤1、2、3

2.2 排序算法

ori_data = [5, 2, 2, 1, 4, 3, 5, 5, 1, 2, 4]
ori_data.sort()
print(ori_data)  # [1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5]


def move_left(data, start_index, end_index):
    right_data = data[end_index]
    for i in range(end_index, start_index):
        data[i] = data[i + 1]
    data[start_index] = right_data


def dispersed_sorted_by_self(original_data):
    for index in range(len(original_data) - 2, -1, -1):
        point = index
        count = 0
        once_traverse = False
        while original_data[point] == original_data[point + 1] or once_traverse:
            p1 = point
            while original_data[point - 1] == original_data[point] or original_data[point - 1] >= original_data[p1 + 1]:
                if point > 1:
                    point -= 1
                    once_traverse = True
                else:
                    once_traverse = False
                    break
            if once_traverse or count == 0:
                p2 = point - 1
                move_left(original_data, p1, p2)
                count += 1
                point = index - count
                once_traverse = True
            else:
                break


if __name__ == "__main__":
    dispersed_sorted_by_self(ori_data)  # 原地排序
    print(ori_data)  # [2, 5, 1, 2, 4, 5, 1, 2, 3, 4, 5]

3、在新的空间进行排序

3.1 提取关键处理

开辟新的数组空间

    steps01    将A1最右边的元素加到A2最左边

    steps02    依次找到第一个与A2[0]不同的元素,插入到A2最左边的位置,其他元素依次插入到A3最左边

    steps03    将A3赋值给A1,依次执行上述过程

3.2 排序算法

from collections import deque

ori_data = [5, 2, 2, 1, 4, 3, 5, 5, 1, 2, 4]
ori_data.sort()
print(ori_data)  # [1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5]


def dispersed_sorted_by_new_space(original_data):
    data_resorted = deque()
    while original_data:
        data_resorted.appendleft(original_data.pop())
        data_remainder = deque()
        for index in range(len(original_data) - 1, -1, -1):
            current_data = original_data[index]
            last_data = data_resorted[0]
            if current_data != last_data:
                data_resorted.appendleft(current_data)
            else:
                data_remainder.appendleft(current_data)
        original_data = data_remainder
    return list(data_resorted)


if __name__ == "__main__":
    dispersed_sorted_by_new_space(ori_data[:])
    print(ori_data)  # [1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5]
    new_data = dispersed_sorted_by_new_space(ori_data[:])
    print(new_data)  # [2, 5, 1, 2, 4, 5, 1, 2, 3, 4, 5]

4、值传递

    在python中,对于像字典、列表、元组等对象,赋值时通常将元素地址赋值过去,并没有开辟新的地址空间,因此不同的变量名指向同一个地址时,若改变其中一个变量的值,另一个会随之改变

    函数的参数传递也是一样的道理,如果传递的变量是字典、列表、元组等对象,会将变量的地址赋值给函数中的形参,那么函数对于形参所做的改变会直接影响原始的值,不需要再做形参的返回

5、两种排序方式对比

        通常情况下列表的原地排序不会开辟新的内存空间,就减少了在函数的调用过程中值传递的次数,但是代码的可读性较差

        而在新空间下进行排序,代码可读性通常更高,时间复杂度也会降低,但是空间复杂度较高

        在实际的开发过程中,如果对于空间复杂度没有具体要求,可以首选第二种排序方式,利于代码的可读和可维护

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值