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