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、两种排序方式对比
通常情况下列表的原地排序不会开辟新的内存空间,就减少了在函数的调用过程中值传递的次数,但是代码的可读性较差
而在新空间下进行排序,代码可读性通常更高,时间复杂度也会降低,但是空间复杂度较高
在实际的开发过程中,如果对于空间复杂度没有具体要求,可以首选第二种排序方式,利于代码的可读和可维护