数据结构与算法之链表 链表分割 三向分区扩展

数据结构与算法阿木 发布于 2025-07-11 8 次阅读


链表分割:三向分区扩展算法解析与实践

链表是一种常见的数据结构,由一系列节点组成,每个节点包含数据和指向下一个节点的指针。链表的操作通常包括插入、删除、查找等。在链表操作中,链表分割是一个重要的操作,它可以将链表分为多个部分,以便进行后续的处理。本文将围绕链表分割这一主题,重点介绍三向分区扩展算法,并对其进行详细解析和实践。

链表分割概述

链表分割是指将链表按照一定的规则划分为多个子链表的过程。分割后的子链表可以具有不同的特性,例如按照值的大小、按照出现频率等。链表分割在数据排序、查找、合并等操作中有着广泛的应用。

三向分区扩展算法

三向分区扩展算法是一种高效的链表分割方法,它基于快速排序的思想,将链表分为三个部分:小于基准值的节点、等于基准值的节点和大于基准值的节点。这种方法在分割过程中不需要额外的存储空间,且分割效率较高。

算法原理

1. 选择一个基准值(pivot),通常选择链表中的第一个节点或最后一个节点。

2. 遍历链表,将每个节点与基准值进行比较,并根据比较结果将其插入到三个指针中:小于基准值的节点指针、等于基准值的节点指针和大于基准值的节点指针。

3. 递归地对小于基准值的节点和大于基准值的节点进行相同的分割操作。

4. 将三个指针指向的子链表连接起来,形成分割后的链表。

代码实现

以下是一个基于C++的三向分区扩展算法的链表分割实现:

cpp

include <iostream>

// 定义链表节点结构体


struct ListNode {


int val;


ListNode next;


ListNode(int x) : val(x), next(nullptr) {}


};

// 三向分区扩展算法


ListNode partition(ListNode head, ListNode &lt, ListNode &eq, ListNode &gt, int pivot) {


if (!head) return nullptr;

ListNode lt_head = nullptr, lt_tail = nullptr;


ListNode eq_head = nullptr, eq_tail = nullptr;


ListNode gt_head = nullptr, gt_tail = nullptr;

while (head) {


ListNode next = head->next;


head->next = nullptr;

if (head->val < pivot) {


if (!lt_head) {


lt_head = lt_tail = head;


} else {


lt_tail->next = head;


lt_tail = head;


}


} else if (head->val == pivot) {


if (!eq_head) {


eq_head = eq_tail = head;


} else {


eq_tail->next = head;


eq_tail = head;


}


} else {


if (!gt_head) {


gt_head = gt_tail = head;


} else {


gt_tail->next = head;


gt_tail = head;


}


}

head = next;


}

lt_tail->next = eq_head;


eq_tail->next = gt_head;

if (!lt_head) return eq_head;


if (!eq_head) return lt_head;

ListNode result = lt_head;


lt_tail = lt_head;


eq_tail = eq_head;

while (eq_tail) {


lt_tail->next = eq_tail;


lt_tail = eq_tail;


eq_tail = eq_tail->next;


}

lt_tail->next = gt_head;


return result;


}

// 主函数


int main() {


// 创建链表


ListNode head = new ListNode(3);


head->next = new ListNode(5);


head->next->next = new ListNode(8);


head->next->next->next = new ListNode(5);


head->next->next->next->next = new ListNode(10);


head->next->next->next->next->next = new ListNode(2);


head->next->next->next->next->next->next = new ListNode(1);

// 分割链表


ListNode lt, eq, gt;


ListNode result = partition(head, lt, eq, gt, 5);

// 打印分割后的链表


std::cout << "Less than pivot: ";


while (lt) {


std::cout << lt->val << " ";


lt = lt->next;


}


std::cout << std::endl;

std::cout << "Equal to pivot: ";


while (eq) {


std::cout << eq->val << " ";


eq = eq->next;


}


std::cout << std::endl;

std::cout << "Greater than pivot: ";


while (gt) {


std::cout << gt->val << " ";


gt = gt->next;


}


std::cout << std::endl;

return 0;


}


算法分析

1. 时间复杂度:平均情况下,三向分区扩展算法的时间复杂度为O(n),其中n为链表长度。最坏情况下,时间复杂度为O(n^2)。

2. 空间复杂度:三向分区扩展算法的空间复杂度为O(1),因为它不需要额外的存储空间。

总结

本文介绍了链表分割的三向分区扩展算法,并对其原理和代码实现进行了详细解析。三向分区扩展算法是一种高效的链表分割方法,在数据排序、查找、合并等操作中有着广泛的应用。通过本文的学习,读者可以更好地理解链表分割算法,并将其应用于实际项目中。