Smaller And Smarter Python数据结构:链表进行重新排序

简介: Smaller And Smarter Python数据结构:链表进行重新排序

简说Python,号主老表,Python终身学习者,数据分析爱好者,从18年开始分享Python知识,原创文章227篇,写过Python、SQL、Excel入门文章,也写过Web开发、数据分析文章,老表还总结整理了一份2022Python学习资料和电子书资源,关注后私信回复:2022 即可领取。

今天给大家分享的书籍《Python程序员面试算法宝典》第一章第四小节:链表进行重新排序。

如果你是第一次看,也许,你可以看看本系列下面的文章:

Smaller And Smarter Python数据结构:链表逆转

Smaller And Smarter Python数据结构:删除无序链表重复结点

Smaller And Smarter Python数据结构:链表相加

今日问题

"""
目标:写一段程序,对链表进行重新排序
例如:
输入-> L1->L2->L3->...->Ln-1->Ln
输出-> L1->Ln->L2->Ln-1...
"""
"""
Objective: write a program to reorder the linked list
For example:
Input - > L1 - > L2 - > L3 -> ... - > ln-1 - > LN
Output - > L1 - > ln - > L2 - > ln-1...
"""

题目要求

(1)在原来链表的基础上进行排序,即不能申请新的结点;

(2)只能修改结点的next域,不能修改数据域。

首先我们写好链表的基本操作,在a_0_base.py文件中,目前包含对链表的定义类,初始化函数,遍历函数。(带头结点)

# -*- coding: utf-8 -*-
"""
@author = 老表
@date = 2019-10-19
@个人微信公众号 : 简说Python
"""
# 链表数据结构定义
class ListNode:
    def __init__(self, x):
        self.data = x
        self.next = None
class ListOperation:
    # 根据链表数据初始化链表
    @staticmethod
    def init_list(n_list):
        # 初始化一个头指针
        head = ListNode("head")
        cur = head
        for i in n_list:
            node = ListNode(i)
            cur.next = node
            cur = node  # 相当于 cur = cur.next,后移
        return head
    # 遍历链表,带头结点
    @staticmethod
    def ergodic_list(head):
        cur = head.next
        while cur:
            print(cur.data)
            cur = cur.next

解题

开始程序前需提前导入前面写好的链表基本操作包,在Linked_list的a_0_base.py中。

from Linked_list.a_0_base import ListOperation

思路分析

"""
核心思想:先将链表前 后段分开,然后将后半段链表逆转,
再遍历链表,将处理好的后半段链表结点插入到前半段链表中。
优点:该题比较综合,遍历链表,逆转链表,插入结点
时间复杂度:O(N)
空间复杂度:O(1)
"""

注意:代码中的注释部分可以不需要,是我自己编写、调试bug时用的,之所以留在上面,主要为了方便大家调试代码和理解代码。

辅助函数:查找链表中间结点

# 辅助函数:找出链表中间结点
def find_mid_link(head):
    fast_node = head.next  # 快指针,每次后移两位
    slow_node = head.next  # 慢指针,每次后移一位
    while fast_node and fast_node.next:  # 遍历链表,快指针遍历结束时,慢指针应该刚好遍历到一半
        pre_slow_node = slow_node  # 记录慢指针前驱结点,方便断开前后半部分链表
        slow_node = slow_node.next  # 慢指针后移,步进1
        fast_node = fast_node.next.next  # 快指针后移,步进2
    pre_slow_node.next = None  # 断开前半部分链表与后半部分链表连接
    return slow_node  # 返回中间结点

辅助函数:不带头结点链表逆转

# 辅助函数:不带头结点链表逆转
def reverse_list(l1):
    if not l1 or not l1.next:  # 空链表或只有一个结点
        return l1
    cur_node = l1.next  # 记录当前结点
    pre_node = l1  # 记录前驱结点
    l1.next = None  # 设置尾结点
    # print("------------------")
    while cur_node:
        # print(cur_node.data)
        next_node = cur_node.next  # 记录后继结点
        cur_node.next = pre_node  # 当前结点反向指向前驱结点
        pre_node = cur_node  # 前驱结点后移
        cur_node = next_node  #  当前结点后移
        # print(pre_node.data)
    return pre_node  # 返回链表表头结点

主功能函数

def reorder_link_one(head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if not head.next:  # 空链表
        return head  # 返回头结点
    mid_node = find_mid_link(head)  # 查找链表中间结点
    # print("------------------")
    # s0 = ListOperation()
    # s0.ergodic_list(mid_node)
    # print("------------------")
    # s0.ergodic_list(head)
    mid_node = reverse_list(mid_node)  # 逆转后半部分链表,无头结点
    # print("------------------")
    # ListOperation.ergodic_list(mid_node)
    cur_node = head.next  # 记录前半段链表第一个结点
    while cur_node.next:  # 遍历前半段结点,将后半段结点插入
        temp_node = cur_node.next  # 记录后继结点
        cur_node.next = mid_node  # 插入
        cur_node = temp_node  # 后移
        temp_node = mid_node.next  # 记录后继结点
        mid_node.next = cur_node  # 插入
        mid_node = temp_node  # 后移
    cur_node.next = mid_node  # 将mid_node最后一个结点插入
    return head  # 返回当前子链表头结点

测试代码

# 当然,也许还有别的方法,比如建一个辅助的链表
# 欢迎你说出你的想法
# 程序入口,测试函数功能
if __name__ == "__main__":
    s0 = ListOperation()  # 初始化一个链表基本操作对象实例
    list_data = [1, 2, 3, 4, 5, 6]  # 链表初始化数据
    head = s0.init_list(list_data)  # 初始化链表,带头结点
    s0.ergodic_list(head)  # 未操作前,遍历打印链表
    head = reorder_link_one(head)  # 测试方法一
    print("---------------------")
    s0.ergodic_list(head)  # 操作后,遍历打印链表

本文代码思路部分来自书籍《Python程序员面试宝典》,书中部分代码有问题或未提供代码,文中已经修改过了,并添加上了丰厚的注释,方便大家学习,后面我会把所有内容开源放到Github上,包括代码,思路,算法图解(手绘或者电脑画),时间充裕的话,会录制视频。

希望大家多多支持。

大家好,我是老表

觉得本文不错的话,转发、留言、点赞,是对我最大的支持。

相关文章
|
2月前
|
Java 数据处理 索引
(Pandas)Python做数据处理必选框架之一!(二):附带案例分析;刨析DataFrame结构和其属性;学会访问具体元素;判断元素是否存在;元素求和、求标准值、方差、去重、删除、排序...
DataFrame结构 每一列都属于Series类型,不同列之间数据类型可以不一样,但同一列的值类型必须一致。 DataFrame拥有一个总的 idx记录列,该列记录了每一行的索引 在DataFrame中,若列之间的元素个数不匹配,且使用Series填充时,在DataFrame里空值会显示为NaN;当列之间元素个数不匹配,并且不使用Series填充,会报错。在指定了index 属性显示情况下,会按照index的位置进行排序,默认是 [0,1,2,3,...] 从0索引开始正序排序行。
243 0
|
2月前
|
Java 数据挖掘 数据处理
(Pandas)Python做数据处理必选框架之一!(一):介绍Pandas中的两个数据结构;刨析Series:如何访问数据;数据去重、取众数、总和、标准差、方差、平均值等;判断缺失值、获取索引...
Pandas 是一个开源的数据分析和数据处理库,它是基于 Python 编程语言的。 Pandas 提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据(类似于Excel表格)。 Pandas 是数据科学和分析领域中常用的工具之一,它使得用户能够轻松地从各种数据源中导入数据,并对数据进行高效的操作和分析。 Pandas 主要引入了两种新的数据结构:Series 和 DataFrame。
390 0
|
9月前
|
存储 人工智能 索引
Python数据结构:列表、元组、字典、集合
Python 中的列表、元组、字典和集合是常用数据结构。列表(List)是有序可变集合,支持增删改查操作;元组(Tuple)与列表类似但不可变,适合存储固定数据;字典(Dictionary)以键值对形式存储,无序可变,便于快速查找和修改;集合(Set)为无序不重复集合,支持高效集合运算如并集、交集等。根据需求选择合适的数据结构,可提升代码效率与可读性。
|
10月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
364 30
|
10月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》图、查找、排序专题考点(含解析)
408考研——《数据结构》图,查找和排序专题考点选择题汇总(含解析)。
634 29
|
10月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
455 25
|
11月前
|
数据挖掘 数据处理 开发者
Python3 自定义排序详解:方法与示例
Python的排序功能强大且灵活,主要通过`sorted()`函数和列表的`sort()`方法实现。两者均支持`key`参数自定义排序规则。本文详细介绍了基础排序、按字符串长度或元组元素排序、降序排序、多条件排序及使用`lambda`表达式和`functools.cmp_to_key`进行复杂排序。通过示例展示了如何对简单数据类型、字典、类对象及复杂数据结构(如列车信息)进行排序。掌握这些技巧可以显著提升数据处理能力,为编程提供更强大的支持。
501 10
|
11月前
|
存储 人工智能 算法
【C++数据结构——内排序】二路归并排序(头歌实践教学平台习题)【合集】
本关任务是实现二路归并算法,即将两个有序数组合并为一个有序数组。主要内容包括: - **任务描述**:实现二路归并算法。 - **相关知识**: - 二路归并算法的基本概念。 - 算法步骤:通过比较两个有序数组的元素,依次将较小的元素放入新数组中。 - 代码示例(以 C++ 为例)。 - 时间复杂度为 O(m+n),空间复杂度为 O(m+n)。 - **测试说明**:平台会对你编写的代码进行测试,提供输入和输出示例。 - **通关代码**:提供了完整的 C++ 实现代码。 - **测试结果**:展示代码运行后的排序结果。 开始你的任务吧,祝你成功!
334 10
|
11月前
|
搜索推荐 算法 数据处理
【C++数据结构——内排序】希尔排序(头歌实践教学平台习题)【合集】
本文介绍了希尔排序算法的实现及相关知识。主要内容包括: - **任务描述**:实现希尔排序算法。 - **相关知识**: - 排序算法基础概念,如稳定性。 - 插入排序的基本思想和步骤。 - 间隔序列(增量序列)的概念及其在希尔排序中的应用。 - 算法的时间复杂度和空间复杂度分析。 - 代码实现技巧,如循环嵌套和索引计算。 - **测试说明**:提供了测试输入和输出示例,帮助验证代码正确性。 - **我的通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了代码运行的测试结果。 通过这些内容,读者可以全面了解希尔排序的原理和实现方法。
251 10

热门文章

最新文章

推荐镜像

更多