| 8 | 6 | 5 | 1 | 3 | 
|---|
因為記憶體是可以隨機存取(random access)的,導致兩種配置方式在資料操作上(e.g., 新增、刪除)的時間及空間成本各有不同。
| Linked List | Array | |
|---|---|---|
| 空間 | 較複雜(需要額外pointer) | 較節省 | 
| 查詢第i個元素 | O(n) | O(1) | 
| 刪除第i個元素 | O(1) | O(n) | 
| 優點 | 大小可不固定 | 隨機存取 | 
typedef struct {
    PyObject_VAR_HEAD
    PyObject **ob_item;
    Py_ssize_t allocated;
} PyListObject;new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
new_allocated += newsize; * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
    
}func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	head := &ListNode{0, nil}
	node := head
	for l1 != nil && l2 != nil {
		if l1.Val <= l2.Val {
			node.Next = l1
			l1 = l1.Next
		} else {
			node.Next = l2
			l2 = l2.Next
		}
        	node = node.Next
	}
    
	if l1 == nil {
		node.Next = l2
	} else {
		node.Next = l1
	}
	return head.Next
}利用dummy node作為起始
func reverseList(head *ListNode) *ListNode {
    
}func reverseList(head *ListNode) *ListNode {
    var front *ListNode
    curr, next := head, head
    for curr != nil {
        next = curr.Next
        curr.Next = front
        front, curr = curr, next
    }
    return front
}front
curr
next
1. 先記住下一個
2. 往回指
3. 更新front, curr
front
curr
func removeNthFromEnd(head *ListNode, n int) *ListNode {
    
}func removeNthFromEnd(head *ListNode, n int) *ListNode {
	start := &ListNode{0, nil}
	b, f := start, start
	b.Next = head
	for i := 0; i <= n; i++ {
		f = f.Next
	}
	for f != nil {
		b = b.Next
		f = f.Next
	}
	b.Next = b.Next.Next
	return start.Next
}假設list長度是m
f先走n -> 剩下m-n
b出發直到f到底 -> 走m-n -> 停在倒數n
func detectCycle(head *ListNode) *ListNode {
    
}func detectCycle(head *ListNode) *ListNode {
    if head == nil || head.Next == nil {
        return nil
    }
    slow, fast := head.Next, head.Next.Next
    for fast != nil && fast.Next != nil && slow != fast {
        slow = slow.Next
        fast = fast.Next.Next
    }
    if fast == slow {
        fast = head
    } else {
        return nil
    }
    for fast != slow {
        fast = fast.Next
        slow = slow.Next
    }
    return slow
}LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // cache is {1=1}
lRUCache.put(2, 2); // cache is {1=1, 2=2}
lRUCache.get(1);    // return 1
lRUCache.put(3, 3); // LRU key was 2, evicts key 2, cache is {1=1, 3=3}
lRUCache.get(2);    // returns -1 (not found)
lRUCache.put(4, 4); // LRU key was 1, evicts key 1, cache is {4=4, 3=3}
lRUCache.get(1);    // return -1 (not found)
lRUCache.get(3);    // return 3
lRUCache.get(4);    // return 4參考jserv: Linked list
以刪除節點為例,考慮到target有可能是head
void remove_list_node(List *list, Node *target)
{
    Node *prev = NULL;
    Node *current = list->head;
    // Walk the list
    while (current != target) {
        prev = current;
        current = current->next;
    }
    // Remove the target by updating the head or the previous node.
    if (!prev)
        list->head = target->next;
    else
        prev->next = target->next;
}void remove_list_node(List *list, Node *target)
{
    Node **indirect = &list->head;
    while (*indirect != target)
        indirect = &(*indirect)->next;
    *indirect = target->next;
}維護指標的指標,檢查需要被更新的位址
原本的作法
利用pointer to pointer
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	head := &ListNode{0, nil}
	node := head
	for l1 != nil && l2 != nil {
		if l1.Val <= l2.Val {
			node.Next = l1
			l1 = l1.Next
		} else {
			node.Next = l2
			l2 = l2.Next
		}
        	node = node.Next
	}
    
	if l1 == nil {
		node.Next = l2
	} else {
		node.Next = l1
	}
	return head.Next
}以剛才的 21. Merge Two Sorted Lists 為例
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
	head := &ListNode{0, nil}
	ptr := &head
	for l1 != nil && l2 != nil {
		if l1.Val < l2.Val {
			*ptr = l1
			l1 = l1.Next
		} else {
			*ptr = l2
			l2 = l2.Next
		}
		ptr = &((*ptr).Next)
	}
	if l1 == nil {
		*ptr = l2
	} else {
		*ptr = l1
	}
	return head
}利用pointer to pointer
利用dummy node
// usually
struct list_node {
	int data;
	struct list_node *next;
}
// linux/scripts/kconfig/list.h
struct list_head {
	struct list_head *next, *prev;
};與常見的linked list 之區別
使用方式如下
struct student
{
    char name[16];
    int id;
    struct list_head list;
};該如何取得 Jerry 的名字?
struct list_node *Jerry_list = (Tom->list).next;
struct student
{
    char name[16];
    int id;
    struct list_head list;
};
struct list_node *Jerry_list = (Tom->list).next;
struct student *Jerry = container_of(Jerry_list, struct student, list);
container_of 這個macro如何實現?
#define container_of(ptr, type, member) ({\
        const typeof( ((type *)0)->member ) *__mptr = (ptr);\
              (type *)( (char *)__mptr - offsetof(type,member));})可拆分成兩部份
const typeof( ((type *)0)->member ) *__mptr = (ptr);以及
(type *)( (char *)__mptr - offsetof(type,member));struct student
{
    char name[16];
    int id;
    struct list_head list;
};| name | 
| id | 
| list | 
x
x+16
x+20
const typeof( ((type *)0)->member ) *__mptr = (ptr);利用ptr得到該member型態同值的__mptr
以member是list為例就是x+20
(但目前不知道offset為20)
(type *)( (char *)__mptr - offsetof(type,member));這段敘述代表以零為起始位址算出member這個成員的相對位址
20
x+20
offsetof 如何實現?
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)將數值 0 強制轉型成TYPE指標型別
0 會被當作該TYPE的起始地址
因為起始位址等於 0
所以MEMBER的位址也就等於MEMBER與起始位址 0 的偏移(offset)。
offsetof(struct student, list)); //20e.g.,
補充: 為何偏移量不是20?
offsetof(struct student, list)); //20struct student
{
    char name[16];
    int id;
    struct list_head list;
};| name | 
| id | 
| list | 
x
x+16
x+20