• 算法导论(第三版)练习 10.2-1 ~ 10.2-7


    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
            <script type="text/javascript">
                let log = console.log.bind(console);
                
                function makeObj(value=0, n=null, p=null) {
                    let obj = {
                        key: value,
                        next: n,
                        prev: p,
                    };        
                    return obj;
                }
                
                function makeLinkedList(arr) {
                    let list = {};
                    list.head = makeObj(arr[0]);
                    let temp = list.head;
                    for (let i = 1; i != arr.length; ++i) {
                        temp.next = makeObj(arr[i]);
                        temp.next.prev = temp;
                        temp = temp.next;
                    }
                    return list;
                }
                
                function listSearch(list, key) {
                    let temp = list.head;
                    while (temp != null && temp.key != key) {
                        temp = temp.next;
                    }
                    return temp;
                }
                
                function listInsert(list, obj) {
                    // 注意是插入到链表的前面
                    obj.next = list.head;
                    if (list.head != null) {
                        list.head.prev = obj;
                    }
                    list.head = obj;
                    
                    return list; // 便于打印。。
                }
                
                function listDelete(list, obj) {
                    // 要拿到相应元素的引用,并且确保obj确实在list里
                    if (obj.prev != null) {
                        obj.prev.next = obj.next;
                    } else {
                        list.head = obj.next;
                    }
                    if (obj.next != null) {
                        obj.next.prev = obj.prev;
                    }
                    
                    return list; // 便于打印。。
                }
                
                let list = makeLinkedList([9, 16, 4, 1]);
                log(list); // 9, 16, 4, 1
                log(listSearch(list, 4));
                log(listInsert(list, makeObj(3))); // 3, 9, 16, 4, 1
                log(listDelete(list, listSearch(list, 4))); // 3, 9, 16, 1
            </script>
            
            <script type="text/javascript">
                /**
                 * 哨兵版本(双向循环列表)。
                 * 不能降低增长量级,但是可以降低常数因子。
                 * 假如有多个很短的链表,它们的哨兵所占用的
                 * 额外存储空间会造成严重的存储浪费。
                 * 注意:哨兵元素是不存储数据的!!!
                 * 空的双向循环列表中仍有一个哨兵元素
                 */
                function makeLinkedList2(arr) {
                    let list = {};
                    list.nil = makeObj(null);
                    let temp = list.nil; 
                    for (let i = 0; i != arr.length; ++i) { 
                        temp.next = makeObj(arr[i]);
                        temp.next.prev = temp;
                        temp = temp.next;
                    }
                    list.nil.prev = temp; 
                    temp.next = list.nil; 
                    return list;
                }    
                
                function listDelete2(list, obj) {
                    // 要拿到相应元素的引用,并且确保obj确实在list里
                    obj.prev.next = obj.next;
                    obj.next.prev = obj.prev;                
                    return list; // 便于打印
                }    
                
                function listSearch2(list, key) {
                    let temp = list.nil.next; // 注意此处的修改
                    while (temp != list.nil && temp.key != key) {
                        temp = temp.next;
                    }
                    return temp;
                }
    
                function listInsert2(list, obj) {
                    obj.next = list.nil.next;
                    list.nil.next.prev = obj;
                    list.nil.next = obj;
                    obj.prev = list.nil;
                    return list; // 便于打印
                }
                
                log("=======list 2=========");
                let list2 = makeLinkedList2([1, 2, 3]);
                log(list2); // null, 1, 2, 3
                log(listSearch2(list2, 3));
                log(listInsert2(list2, makeObj(4))); // null, 4, 1, 2, 3
                let x = listSearch2(list2, 4);
                log(listDelete2(list2, x)); // null, 1, 2, 3
            </script>
        </body>
    </html>
    双向链表+有哨兵的双向循环链表

    10.2-1

    这个得区分往哪insert,以及delete是指定delete还是delete首元素或者尾元素。

    如果按照书上的算法:insert可以,delete不行。

    10.2-2

    10.2-3

    10.2-4

    该检查的目的就在于防止死循环,解决这个问题,只要把k作为哨兵关键字key的value就可以了。在搜索结束后再把空值赋还给哨兵。

    10.2-5

    实现略。

    按照书上的算法:INSERT是O(1),DELETE是O(n),SEARCH也是O(n)

    10.2-6

    双向循环链表。直接把一个链表接到另外一个链表的首尾都可以。如果有中间元素的引用,直接往中间插也是O(1)的。

    10.2-7

    扫描一遍list,把next反向指一下就行了。需要一个额外的temp临时存储下一个元素。

  • 相关阅读:
    AD读取Excel新建客户邮箱的测试环境部署有感
    云端转发邮箱
    AD活动目录操作软件设计节选
    14)
    13)
    行级,块级,空
    12)
    11)
    10)
    9)
  • 原文地址:https://www.cnblogs.com/xkxf/p/9987019.html
Copyright © 2020-2023  润新知