荷兰国旗问题—单链表额外空间复杂度O(1) 解法

这篇博客探讨了荷兰国旗问题,特别是在单链表上的实现。内容包括问题描述、数组存储序列的快排方案及步骤,以及针对单链表存储序列的额外空间复杂度为O(1)的稳定解决方案,通过拆分和重组链表实现小于、等于和大于pivot的元素排序。
摘要由CSDN通过智能技术生成

描述

假设有一个整数序列,要求将大于 pivot 的数放在序列右边,小于 pivot 的数放在序列左边,等于 pivot 的数放在序列中间。

分析

荷兰国旗问题本质是一个序列分割问题,需要将一个序列分割成三部分。有一个很关键的地方,就是整个序列究竟存储在什么数据结构中。如果序列存储在顺序数组中,那么使用一趟快排即可。如果存储在单链表中,由于一趟快排的过程中会发生许多随机存取,在单链表上随机存取的代价十分高昂。因此对于单链表不适用快排。

数组存储序列

方案

使用一趟快排解决问题。时间复杂度为 O(N),额外空间复杂度为 O(N),不稳定。
排序前:
在这里插入图片描述
排序过程:
在这里插入图片描述

步骤

① 准备三个指针 less、more、cur。less 的初值为排序范围的左边界减 1,more 为右边界减 1,cur 为左边界。
② 判断 cur 与 pivot 的大小。如果 cur > pivot,cur 和 --more 交换。
如果 cur < pivot,cur 和 ++less 交换,并且 cur 右移一步。
如果 cur == pivot,cur 直接右移一步。
③ 重复 ②,直到 cur >= more。

代码
class DutchNationalFlagProblem {
   
    public static void main(String[] args) {
   
        // 原始数组
        int[] a = {
   3,4,9,5,7,1,0,5,2,8,5,6};
        // 打印原始数组
        for (int i = 0; i < a.length; i++) {
                   
            System.out.print(a[i] + " ");
        }    
        System.out.println(); 
        dutchNationalFlagProblem(a, 5);
        // 打印排序后的数组                     
        for (int i = 0; i < a.length; i++) {
                   
            System.out.print(a[i] + " ");
        }
        System.out.println();
    }
    public static void dutchNationalFlagProblem(int[] a, int pivot) {
   
        // 一趟快排解决荷兰国旗问题
        quickSort(a, 0, a.length - 1, pivot);
    }
    /**
     * 一趟快排的例程
     * @param a 待排序数组
     * @param left  排序范围的左边界
     * @param right 排序范围的右边界
     * @param pivot
     */
    public static void quickSort(int[] a, int left, int right, int pivot) {
   
        int less = left - 1;                                // less 初始值为左边界减1
        int more = right + 1;                               // more 初始值为有边界加1
        int cur = left;                                     // cur 初始值为左边界
        while (cur < more) {
                                   // cur >= more 循环停止
            if (a[cur] > pivot) {
                              // 如果 cur > pivot,cur 和 --more 交换
                swap(a, cur, --more);
            } else if (a[cur] < pivot) {
                       // 如果 cur < prvot,cur 和 ++less 交换,且 curr 右移一步
                swap(a, cur, ++less);
                cur++;
            } else {
                                           // 如果 cur == pivot,cur直接右移一步
                cur++;
            }
        }
    }
    // 交换数组中指定两个下标的元素
    private static void swap(int[] a, int m, int n) {
   
        int temp = a[m];
        a[m] = a[n];
        a[n] = temp;
    }
}

out:
3 4 9 5 7 1 0 5 2 8 5 6
3 4 2 1 0 5 5 5 8 7 6 9

单链表存储序列

方案

如果实际问题对于空间复杂度和稳定性没有要求,完全可以将单链表中的元素值先存储到一个顺序数组中,再对这个数组使用一趟快排。如果实际问题要求额外空间复杂度为 O(1) 且保证算法稳定性,可以使用先拆后合的策略。将一个链表拆成三个链表 less、equal、more。less 链表按原链表先后次序存放小于 pivot 的节点。equal 链表存放等于 pivot 的节点。more 链表存放大于 pivot 的节点。最后再将三个链表接起来即可。
排序前:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值