算法导论(第三版)练习 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临时存储下一个元素。

原文地址:https://www.cnblogs.com/xkxf/p/9987019.html