算法笔记-快速排序(Quick Sort)之Duplicate Keys

本文介绍了在快速排序中遇到重复元素(重复键)时如何使用3-way partitioning方法进行处理,确保排序正确。通过一系列步骤展示了算法如何区分小于、等于和大于pivot的元素,并给出了Java实现的上下文。

问题描述:
当数组中有很多重复的元素(Dupicate Keys)时,采用3-way partitioning,即把array分成三部分,一部分是小于duplicate keys的,一部分是等于duplicate keys,还有一部分是大于duplicate keys。当然,一轮partition只能让一种duplicate keys归位,如果其他数字也有duplicate的情况,则需要进行下一轮partition。

Goal:
Goal

算法思路:

  • a[lo]作为pivot
  • 从左向右扫描i(其实一直都是a[i]和pivot在比较)
    • (a[i] < pivot): 交换a[lt]和a[i]; lt, i同时加1。
    • (a[i] > pivot): 交换a[gt]和a[i]; gt减1。(i不变,因为交换后的i指向的元素还没有和a[lt]比较)
    • (a[i] == pivot): i加1。
      invariant

demo:
1. 初始化。
in
2. i+1,这一轮partitioning element是P;lt->P, i->A
2
3. A<<P, 故a[lt]和a[i]交换,且lt, i同时+1;lt->P, i->B (lt一直指向partitioning element)
3
4. B<<P, 故a[lt]和a[i]交换,且lt, i同时+1;lt->P, i->X
4
5. X>>P, 故a[gt]和a[i]交换,且gt-1;i->Z, gt->Y(gt已经减1了)
5
6. Z>P, 故a[gt]和a[i]交换,且gt-1;i->Y, gt->C
6
7. Y>>P, 故a[gt]和a[i]交换,且gt-1;i->C, gt->P
7
8. C<P, 故a[lt]和a[i]交换,且lt, i同时+1;lt->P, i->W
8
9. W>>P, 故a[gt]和a[i]交换,且gt-1;i->P, gt->D
9
10. P=P, 故i++; lt->P, i->P
10
11. P=P, 故i++; lt->P, i->P
11
12. P=P, 故i++; lt->, i->V
12
13. V>P, 故 a[gt]和a[i]交换,且gt-1;i->D, gt->P
13
14. D<<P, 故a[lt]和a[i]交换,且lt, i同时+1;lt->P, i->P [此时pointers cross说明所有数都被scan过了]
14

Language: Java
a

private static void sort(Comparable[] a, int lo, int hi)
{
    if (hi <= lo) return;
    int lt = lo, gt = hi;
    Comparable v = a[lo];
    int i = lo;
    while(i <= gt)
    {
        int cmp = a[i].compareTo(v);
        if(cmp < 0)
            swap(a[lt++], a[i++]);
        else if(cmp > 0) 
            swap(a[i], a[gt--]);
        else i++;
}

sort(a, lo, lt - 1);
sort(a, gt + 1, hi);
}

图片来源:Coursera
参考资料:Algorothm 4th

Happy Coding!

### 关于 `el-table` 展开折叠时出现 `Duplicate keys detected` 的解决方案 当使用 Vue 和 Element UI 中的 `el-table` 组件时,如果遇到 `Duplicate keys detected: 'XXX'. This may cause an update error.` 这样的错误提示,通常是因为在渲染表格数据的过程中存在重复的键值。这种问题可能发生在处理树形结构的数据或者动态更新表格内容的情况下。 #### 原因分析 该问题的根本原因在于 Vue 需要通过唯一的 key 来追踪每个节点的状态以便高效地进行 DOM 更新[^2]。如果没有提供唯一的 key 或者提供的 key 不够唯一,则会触发上述警告并可能导致组件行为异常。对于 `el-table` 而言,尤其是在涉及树形数据或可展开行的功能时,必须为每一行指定一个全局唯一的标识符作为 row-key[^3]。 #### 解决方案 以下是几种常见的解决办法: 1. **确保每条记录都有唯一 ID** 如果您的数据源中已经包含了可以充当唯一标识的字段(比如 id),可以直接将其设置为 table 的 `row-key` 属性。 ```vue <template> <el-table :data="tableData" row-key="id"> <!-- 表格列配置 --> </el-table> </template> <script> export default { data() { return { tableData: [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' } ] }; } }; </script> ``` 2. **自动生成唯一 Key** 若原始数据缺乏可用作唯一标识的字段,可以在加载数据前手动添加一个新的属性来存储 UUID 或其他形式的唯一值。 ```javascript this.tableData.forEach(item => { item.uniqueKey = Date.now() + Math.random().toString(36).substr(2); // 创建伪随机数 }); ``` 然后将新创建的 uniqueKey 设置给 `row-key`: ```vue <el-table :data="tableData" row-key="uniqueKey"> <!-- 列定义 --> </el-table> ``` 3. **调试与验证 Data 结构** 在某些情况下,即使设置了 `row-key`,仍然可能出现此问题。这可能是由于嵌套对象内部也缺少必要的唯一性标记所致。因此建议仔细检查整个数据模型是否存在潜在冲突,并适当调整其设计以满足框架需求[^1]。 4. **注意 v-if/v-for 同步关系** 当在同一模板内同时运用条件渲染指令 (`v-if`) 及列表遍历语法(`v-for`)时需格外小心,因为它们可能会干扰到虚拟DOM计算过程中的key分配逻辑。尽量避免两者紧邻放置的情况发生。 以上方法能够有效缓解乃至彻底消除由重复keys引发的一系列麻烦事态发展下去的话将会带来更多的不便之处所以尽早采取措施加以防范是非常重要的一步棋子而已啦! ```python def generate_unique_key(): import time, random return str(int(time.time())) + str(random.randint(0,999)).zfill(3) for i in range(len(data)): data[i]['custom_id'] = generate_unique_key() ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值