0707-设计链表

Raphael Liu Lv10

你可以选择使用单链表或者双链表,设计并实现自己的链表。

单链表中的节点应该具备两个属性:valnextval 是当前节点的值,next 是指向下一个节点的指针/引用。

如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。

实现 MyLinkedList 类:

  • MyLinkedList() 初始化 MyLinkedList 对象。
  • int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1
  • void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
  • void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
  • void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
  • void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。

示例:

**输入**
["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]
[[], [1], [3], [1, 2], [1], [1], [1]]
**输出**
[null, null, null, null, 2, null, 3]

**解释**
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addAtHead(1);
myLinkedList.addAtTail(3);
myLinkedList.addAtIndex(1, 2);    // 链表变为 1->2->3
myLinkedList.get(1);              // 返回 2
myLinkedList.deleteAtIndex(1);    // 现在,链表变为 1->3
myLinkedList.get(1);              // 返回 3

提示:

  • 0 <= index, val <= 1000
  • 请不要使用内置的 LinkedList 库。
  • 调用 getaddAtHeadaddAtTailaddAtIndexdeleteAtIndex 的次数不超过 2000

方法一:单向链表

思路

实现单向链表,即每个节点仅存储本身的值和后继节点。除此之外,我们还需要一个哨兵(sentinel)节点作为头节点,和一个 size 参数保存有效节点数。如下图所示。
img

初始化时,只需创建头节点 head 和 size 即可。

实现 get}(\textit{index}) 时,先判断有效性,再通过循环来找到对应的节点的值。如下图所示。
img

实现 addAtIndex}(\textit{index, val}) 时,如果 index 是有效值,则需要找到原来下标为 index 的节点的前驱节点 pred,并创建新节点 to_add,将to_add 的后继节点设为 pred 的后继节点,将 pred 的后继节点更新为 to_add,这样就将 to_add 插入到了链表中。最后需要更新 size。这样的操作对于 index} = 0 也成立,如以下两张图所示。
img
img

实现 addAtHead}(\textit{val}) 和 addAtTail}(\textit{val}) 时,可以借助 addAtIndex}(\textit{index, val}) 来实现。

实现 deleteAtIndex}(\textit{index}),先判断参数有效性。然后找到下标为 index 的节点的前驱节点 pred,通过将 pred 的后继节点更新为 pred 的后继节点的后继节点,来达到删除节点的效果。同时也要更新 size。如下图所示。
img

代码

[sol1-Python3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class ListNode:

def __init__(self, val):
self.val = val
self.next = None


class MyLinkedList:

def __init__(self):
self.size = 0
self.head = ListNode(0)


def get(self, index: int) -> int:
if index < 0 or index >= self.size:
return -1
cur = self.head
for _ in range(index + 1):
cur = cur.next
return cur.val


def addAtHead(self, val: int) -> None:
self.addAtIndex(0, val)


def addAtTail(self, val: int) -> None:
self.addAtIndex(self.size, val)


def addAtIndex(self, index: int, val: int) -> None:
if index > self.size:
return
index = max(0, index)
self.size += 1
pred = self.head
for _ in range(index):
pred = pred.next
to_add = ListNode(val)
to_add.next = pred.next
pred.next = to_add

def deleteAtIndex(self, index: int) -> None:
if index < 0 or index >= self.size:
return
self.size -= 1
pred = self.head
for _ in range(index):
pred = pred.next
pred.next = pred.next.next
[sol1-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
class MyLinkedList {
int size;
ListNode head;

public MyLinkedList() {
size = 0;
head = new ListNode(0);
}

public int get(int index) {
if (index < 0 || index >= size) {
return -1;
}
ListNode cur = head;
for (int i = 0; i <= index; i++) {
cur = cur.next;
}
return cur.val;
}

public void addAtHead(int val) {
addAtIndex(0, val);
}

public void addAtTail(int val) {
addAtIndex(size, val);
}

public void addAtIndex(int index, int val) {
if (index > size) {
return;
}
index = Math.max(0, index);
size++;
ListNode pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
ListNode toAdd = new ListNode(val);
toAdd.next = pred.next;
pred.next = toAdd;
}

public void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
size--;
ListNode pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
pred.next = pred.next.next;
}
}

class ListNode {
int val;
ListNode next;

public ListNode(int val) {
this.val = val;
}
}
[sol1-C#]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public class MyLinkedList {
int size;
ListNode head;

public MyLinkedList() {
size = 0;
head = new ListNode(0);
}

public int Get(int index) {
if (index < 0 || index >= size) {
return -1;
}
ListNode cur = head;
for (int i = 0; i <= index; i++) {
cur = cur.next;
}
return cur.val;
}

public void AddAtHead(int val) {
AddAtIndex(0, val);
}

public void AddAtTail(int val) {
AddAtIndex(size, val);
}

public void AddAtIndex(int index, int val) {
if (index > size) {
return;
}
index = Math.Max(0, index);
size++;
ListNode pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
ListNode toAdd = new ListNode(val);
toAdd.next = pred.next;
pred.next = toAdd;
}

public void DeleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
size--;
ListNode pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
pred.next = pred.next.next;
}
}

class ListNode {
public int val;
public ListNode next;

public ListNode(int val) {
this.val = val;
}
}
[sol1-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class MyLinkedList {
public:
MyLinkedList() {
this->size = 0;
this->head = new ListNode(0);
}

int get(int index) {
if (index < 0 || index >= size) {
return -1;
}
ListNode *cur = head;
for (int i = 0; i <= index; i++) {
cur = cur->next;
}
return cur->val;
}

void addAtHead(int val) {
addAtIndex(0, val);
}

void addAtTail(int val) {
addAtIndex(size, val);
}

void addAtIndex(int index, int val) {
if (index > size) {
return;
}
index = max(0, index);
size++;
ListNode *pred = head;
for (int i = 0; i < index; i++) {
pred = pred->next;
}
ListNode *toAdd = new ListNode(val);
toAdd->next = pred->next;
pred->next = toAdd;
}

void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
size--;
ListNode *pred = head;
for (int i = 0; i < index; i++) {
pred = pred->next;
}
ListNode *p = pred->next;
pred->next = pred->next->next;
delete p;
}
private:
int size;
ListNode *head;
};
[sol1-C]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#define MAX(a, b) ((a) > (b) ? (a) : (b))

typedef struct {
struct ListNode *head;
int size;
} MyLinkedList;

struct ListNode *ListNodeCreat(int val) {
struct ListNode * node = (struct ListNode *)malloc(sizeof(struct ListNode));
node->val = val;
node->next = NULL;
return node;
}

MyLinkedList* myLinkedListCreate() {
MyLinkedList * obj = (MyLinkedList *)malloc(sizeof(MyLinkedList));
obj->head = ListNodeCreat(0);
obj->size = 0;
return obj;
}

int myLinkedListGet(MyLinkedList* obj, int index) {
if (index < 0 || index >= obj->size) {
return -1;
}
struct ListNode *cur = obj->head;
for (int i = 0; i <= index; i++) {
cur = cur->next;
}
return cur->val;
}

void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
if (index > obj->size) {
return;
}
index = MAX(0, index);
obj->size++;
struct ListNode *pred = obj->head;
for (int i = 0; i < index; i++) {
pred = pred->next;
}
struct ListNode *toAdd = ListNodeCreat(val);
toAdd->next = pred->next;
pred->next = toAdd;
}

void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
myLinkedListAddAtIndex(obj, 0, val);
}

void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
myLinkedListAddAtIndex(obj, obj->size, val);
}

void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
if (index < 0 || index >= obj->size) {
return;
}
obj->size--;
struct ListNode *pred = obj->head;
for (int i = 0; i < index; i++) {
pred = pred->next;
}
struct ListNode *p = pred->next;
pred->next = pred->next->next;
free(p);
}

void myLinkedListFree(MyLinkedList* obj) {
struct ListNode *cur = NULL, *tmp = NULL;
for (cur = obj->head; cur;) {
tmp = cur;
cur = cur->next;
free(tmp);
}
free(obj);
}
[sol1-JavaScript]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
var MyLinkedList = function() {
this.size = 0;
this.head = new ListNode(0);
};

MyLinkedList.prototype.get = function(index) {
if (index < 0 || index >= this.size) {
return -1;
}
let cur = this.head;
for (let i = 0; i <= index; i++) {
cur = cur.next;
}
return cur.val;
};

MyLinkedList.prototype.addAtHead = function(val) {
this.addAtIndex(0, val);
};

MyLinkedList.prototype.addAtTail = function(val) {
this.addAtIndex(this.size, val);
};

MyLinkedList.prototype.addAtIndex = function(index, val) {
if (index > this.size) {
return;
}
index = Math.max(0, index);
this.size++;
let pred = this.head;
for (let i = 0; i < index; i++) {
pred = pred.next;
}
let toAdd = new ListNode(val);
toAdd.next = pred.next;
pred.next = toAdd;
};

MyLinkedList.prototype.deleteAtIndex = function(index) {
if (index < 0 || index >= this.size) {
return;
}
this.size--;
let pred = this.head;
for (let i = 0; i < index; i++) {
pred = pred.next;
}
pred.next = pred.next.next;
};

function ListNode(val, next) {
this.val = (val===undefined ? 0 : val)
this.next = (next===undefined ? null : next)
}
[sol1-Golang]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
type MyLinkedList struct {
head *ListNode
size int
}

func Constructor() MyLinkedList {
return MyLinkedList{&ListNode{}, 0}
}

func (l *MyLinkedList) Get(index int) int {
if index < 0 || index >= l.size {
return -1
}
cur := l.head
for i := 0; i <= index; i++ {
cur = cur.Next
}
return cur.Val
}

func (l *MyLinkedList) AddAtHead(val int) {
l.AddAtIndex(0, val)
}

func (l *MyLinkedList) AddAtTail(val int) {
l.AddAtIndex(l.size, val)
}

func (l *MyLinkedList) AddAtIndex(index, val int) {
if index > l.size {
return
}
index = max(index, 0)
l.size++
pred := l.head
for i := 0; i < index; i++ {
pred = pred.Next
}
toAdd := &ListNode{val, pred.Next}
pred.Next = toAdd
}

func (l *MyLinkedList) DeleteAtIndex(index int) {
if index < 0 || index >= l.size {
return
}
l.size--
pred := l.head
for i := 0; i < index; i++ {
pred = pred.Next
}
pred.Next = pred.Next.Next
}

func max(a, b int) int {
if b > a {
return b
}
return a
}

复杂度分析

  • 时间复杂度:初始化消耗 O(1),get 消耗 O(\textit{index}),addAtHead 消耗 O(1),addAtTail 消耗 O(n),其中 n 为链表当前长度,即 addAtHead,addAtTail 和 addAtIndex 已调用次数之和,addAtIndex 消耗 O(\textit{index})。

  • 空间复杂度:所有函数的单次调用空间复杂度均为 O(1),总体空间复杂度为 O(n),其中 n 为 addAtHead,addAtTail 和 addAtIndex 调用次数之和。

方法二:双向链表

思路

实现双向链表,即每个节点要存储本身的值,后继节点和前驱节点。除此之外,需要一个哨兵节点作为头节点 head 和一个哨兵节点作为尾节点 tail。仍需要一个 size 参数保存有效节点数。如下图所示。
img

初始化时,只需创建头节点 head 和 size 即可。

实现 get}(\textit{index}) 时,先判断有效性,然后再比较从 head 还是 tail 来遍历会比较快找到目标,然后进行遍历。如下图所示。
img

实现 addAtIndex}(\textit{index, val}) 时,如果 index 是有效值,则需要找到原来下标为 index 的节点 succ 和前驱节点 pred,并创建新节点 to_add,再通过各自 prev 和 next 变量的更新来增加 to_add。最后需要更新 size。如以下两张图所示。
img

实现 addAtHead}(\textit{val}) 和 addAtTail}(\textit{val}) 时,可以借助 addAtIndex}(\textit{index, val}) 来实现。

实现 deleteAtIndex}(\textit{index}),先判断参数有效性。然后找到下标为 index 的节点的前驱节点 pred 和后继节点 succ,再通过各自 prev 和 next 变量的更新来删除节点,来达到删除节点的效果。同时也要更新 size。如下图所示。
img

代码

[sol2-Python3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
class ListNode:

def __init__(self, x):
self.val = x
self.next = None
self.prev = None


class MyLinkedList:

def __init__(self):
self.size = 0
self.head, self.tail = ListNode(0), ListNode(0)
self.head.next = self.tail
self.tail.prev = self.head


def get(self, index: int) -> int:
if index < 0 or index >= self.size:
return -1
if index + 1 < self.size - index:
curr = self.head
for _ in range(index + 1):
curr = curr.next
else:
curr = self.tail
for _ in range(self.size - index):
curr = curr.prev
return curr.val


def addAtHead(self, val: int) -> None:
self.addAtIndex(0, val)


def addAtTail(self, val: int) -> None:
self.addAtIndex(self.size, val)


def addAtIndex(self, index: int, val: int) -> None:
if index > self.size:
return
index = max(0, index)
if index < self.size - index:
pred = self.head
for _ in range(index):
pred = pred.next
succ = pred.next
else:
succ = self.tail
for _ in range(self.size - index):
succ = succ.prev
pred = succ.prev
self.size += 1
to_add = ListNode(val)
to_add.prev = pred
to_add.next = succ
pred.next = to_add
succ.prev = to_add


def deleteAtIndex(self, index: int) -> None:
if index < 0 or index >= self.size:
return
if index < self.size - index:
pred = self.head
for _ in range(index):
pred = pred.next
succ = pred.next.next
else:
succ = self.tail
for _ in range(self.size - index - 1):
succ = succ.prev
pred = succ.prev.prev
self.size -= 1
pred.next = succ
succ.prev = pred
[sol2-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
class MyLinkedList {
int size;
ListNode head;
ListNode tail;

public MyLinkedList() {
size = 0;
head = new ListNode(0);
tail = new ListNode(0);
head.next = tail;
tail.prev = head;
}

public int get(int index) {
if (index < 0 || index >= size) {
return -1;
}
ListNode curr;
if (index + 1 < size - index) {
curr = head;
for (int i = 0; i <= index; i++) {
curr = curr.next;
}
} else {
curr = tail;
for (int i = 0; i < size - index; i++) {
curr = curr.prev;
}
}
return curr.val;
}

public void addAtHead(int val) {
addAtIndex(0, val);
}

public void addAtTail(int val) {
addAtIndex(size, val);
}

public void addAtIndex(int index, int val) {
if (index > size) {
return;
}
index = Math.max(0, index);
ListNode pred, succ;
if (index < size - index) {
pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
succ = pred.next;
} else {
succ = tail;
for (int i = 0; i < size - index; i++) {
succ = succ.prev;
}
pred = succ.prev;
}
size++;
ListNode toAdd = new ListNode(val);
toAdd.prev = pred;
toAdd.next = succ;
pred.next = toAdd;
succ.prev = toAdd;
}

public void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
ListNode pred, succ;
if (index < size - index) {
pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
succ = pred.next.next;
} else {
succ = tail;
for (int i = 0; i < size - index - 1; i++) {
succ = succ.prev;
}
pred = succ.prev.prev;
}
size--;
pred.next = succ;
succ.prev = pred;
}
}

class ListNode {
int val;
ListNode next;
ListNode prev;

public ListNode(int val) {
this.val = val;
}
}
[sol2-C#]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
public class MyLinkedList {
int size;
ListNode head;
ListNode tail;

public MyLinkedList() {
size = 0;
head = new ListNode(0);
tail = new ListNode(0);
head.next = tail;
tail.prev = head;
}

public int Get(int index) {
if (index < 0 || index >= size) {
return -1;
}
ListNode curr;
if (index + 1 < size - index) {
curr = head;
for (int i = 0; i <= index; i++) {
curr = curr.next;
}
} else {
curr = tail;
for (int i = 0; i < size - index; i++) {
curr = curr.prev;
}
}
return curr.val;
}

public void AddAtHead(int val) {
AddAtIndex(0, val);
}

public void AddAtTail(int val) {
AddAtIndex(size, val);
}

public void AddAtIndex(int index, int val) {
if (index > size) {
return;
}
index = Math.Max(0, index);
ListNode pred, succ;
if (index < size - index) {
pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
succ = pred.next;
} else {
succ = tail;
for (int i = 0; i < size - index; i++) {
succ = succ.prev;
}
pred = succ.prev;
}
size++;
ListNode toAdd = new ListNode(val);
toAdd.prev = pred;
toAdd.next = succ;
pred.next = toAdd;
succ.prev = toAdd;
}

public void DeleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
ListNode pred, succ;
if (index < size - index) {
pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
succ = pred.next.next;
} else {
succ = tail;
for (int i = 0; i < size - index - 1; i++) {
succ = succ.prev;
}
pred = succ.prev.prev;
}
size--;
pred.next = succ;
succ.prev = pred;
}
}

class ListNode {
public int val;
public ListNode next;
public ListNode prev;

public ListNode(int val) {
this.val = val;
}
}
[sol2-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
struct DLinkListNode {
int val;
DLinkListNode *prev, *next;
DLinkListNode(int _val) : val(_val), prev(nullptr), next(nullptr) {}
};

class MyLinkedList {
public:
MyLinkedList() {
this->size = 0;
this->head = new DLinkListNode(0);
this->tail = new DLinkListNode(0);
head->next = tail;
tail->prev = head;
}

int get(int index) {
if (index < 0 || index >= size) {
return -1;
}
DLinkListNode *curr;
if (index + 1 < size - index) {
curr = head;
for (int i = 0; i <= index; i++) {
curr = curr->next;
}
} else {
curr = tail;
for (int i = 0; i < size - index; i++) {
curr = curr->prev;
}
}
return curr->val;
}

void addAtHead(int val) {
addAtIndex(0, val);
}

void addAtTail(int val) {
addAtIndex(size, val);
}

void addAtIndex(int index, int val) {
if (index > size) {
return;
}
index = max(0, index);
DLinkListNode *pred, *succ;
if (index < size - index) {
pred = head;
for (int i = 0; i < index; i++) {
pred = pred->next;
}
succ = pred->next;
} else {
succ = tail;
for (int i = 0; i < size - index; i++) {
succ = succ->prev;
}
pred = succ->prev;
}
size++;
DLinkListNode *toAdd = new DLinkListNode(val);
toAdd->prev = pred;
toAdd->next = succ;
pred->next = toAdd;
succ->prev = toAdd;
}

void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
DLinkListNode *pred, *succ;
if (index < size - index) {
pred = head;
for (int i = 0; i < index; i++) {
pred = pred->next;
}
succ = pred->next->next;
} else {
succ = tail;
for (int i = 0; i < size - index - 1; i++) {
succ = succ->prev;
}
pred = succ->prev->prev;
}
size--;
DLinkListNode *p = pred->next;
pred->next = succ;
succ->prev = pred;
delete p;
}
private:
int size;
DLinkListNode *head;
DLinkListNode *tail;
};
[sol2-C]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#define MAX(a, b) ((a) > (b) ? (a) : (b))

typedef struct DLinkListNode {
int val;
struct DLinkListNode *prev, *next;
} DLinkListNode;

typedef struct {
struct DLinkListNode *head, *tail;
int size;
} MyLinkedList;

DLinkListNode *dLinkListNodeCreat(int val) {
DLinkListNode * node = (DLinkListNode *)malloc(sizeof(struct DLinkListNode));
node->val = val;
node->prev = NULL;
node->next = NULL;
return node;
}

MyLinkedList* myLinkedListCreate() {
MyLinkedList * obj = (MyLinkedList *)malloc(sizeof(MyLinkedList));
obj->size = 0;
obj->head = dLinkListNodeCreat(0);
obj->tail = dLinkListNodeCreat(0);
obj->head->next = obj->tail;
obj->tail->prev = obj->head;
return obj;
}

int myLinkedListGet(MyLinkedList* obj, int index) {
if (index < 0 || index >= obj->size) {
return -1;
}
DLinkListNode *curr;
if (index + 1 < obj->size - index) {
curr = obj->head;
for (int i = 0; i <= index; i++) {
curr = curr->next;
}
} else {
curr = obj->tail;
for (int i = 0; i < obj->size - index; i++) {
curr = curr->prev;
}
}
return curr->val;
}

void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
if (index > obj->size) {
return;
}
index = MAX(0, index);
DLinkListNode *pred, *succ;
if (index < obj->size - index) {
pred = obj->head;
for (int i = 0; i < index; i++) {
pred = pred->next;
}
succ = pred->next;
} else {
succ = obj->tail;
for (int i = 0; i < obj->size - index; i++) {
succ = succ->prev;
}
pred = succ->prev;
}
obj->size++;
DLinkListNode *toAdd = dLinkListNodeCreat(val);
toAdd->prev = pred;
toAdd->next = succ;
pred->next = toAdd;
succ->prev = toAdd;
}

void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
myLinkedListAddAtIndex(obj, 0, val);
}

void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
myLinkedListAddAtIndex(obj, obj->size, val);
}

void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
if (index < 0 || index >= obj->size) {
return;
}
DLinkListNode *pred, *succ;
if (index < obj->size - index) {
pred = obj->head;
for (int i = 0; i < index; i++) {
pred = pred->next;
}
succ = pred->next->next;
} else {
succ = obj->tail;
for (int i = 0; i < obj->size - index - 1; i++) {
succ = succ->prev;
}
pred = succ->prev->prev;
}
obj->size--;
DLinkListNode *p = pred->next;
pred->next = succ;
succ->prev = pred;
free(p);
}

void myLinkedListFree(MyLinkedList* obj) {
struct DLinkListNode *cur = NULL, *tmp = NULL;
for (cur = obj->head; cur;) {
tmp = cur;
cur = cur->next;
free(tmp);
}
free(obj);
}
[sol2-JavaScript]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
var MyLinkedList = function() {
this.size = 0;
this.head = new ListNode(0);
this.tail = new ListNode(0);
this.head.next = this.tail;
this.tail.prev = this.head;
};

MyLinkedList.prototype.get = function(index) {
if (index < 0 || index >= this.size) {
return -1;
}
let curr;
if (index + 1 < this.size - index) {
curr = this.head;
for (let i = 0; i <= index; i++) {
curr = curr.next;
}
} else {
curr = this.tail;
for (let i = 0; i < this.size - index; i++) {
curr = curr.prev;
}
}
return curr.val;
};

MyLinkedList.prototype.addAtHead = function(val) {
this.addAtIndex(0, val);
};

MyLinkedList.prototype.addAtTail = function(val) {
this.addAtIndex(this.size, val);
};

MyLinkedList.prototype.addAtIndex = function(index, val) {
if (index > this.size) {
return;
}
index = Math.max(0, index);
let pred, succ;
if (index < this.size - index) {
pred = this.head;
for (let i = 0; i < index; i++) {
pred = pred.next;
}
succ = pred.next;
} else {
succ = this.tail;
for (let i = 0; i < this.size - index; i++) {
succ = succ.prev;
}
pred = succ.prev;
}
this.size++;
const toAdd = new ListNode(val);
toAdd.prev = pred;
toAdd.next = succ;
pred.next = toAdd;
succ.prev = toAdd;
};

MyLinkedList.prototype.deleteAtIndex = function(index) {
if (index < 0 || index >= this.size) {
return;
}
let pred, succ;
if (index < this.size - index) {
pred = this.head;
for (let i = 0; i < index; i++) {
pred = pred.next;
}
succ = pred.next.next;
} else {
succ = this.tail;
for (let i = 0; i < this.size - index - 1; i++) {
succ = succ.prev;
}
pred = succ.prev.prev;
}
this.size--;
pred.next = succ;
succ.prev = pred;
};

function ListNode(val, next, prev) {
this.val = (val===undefined ? 0 : val)
this.next = (next===undefined ? null : next)
this.prev = (prev===undefined ? null : next)
}
[sol2-Golang]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
type node struct {
val int
next, prev *node
}

type MyLinkedList struct {
head, tail *node
size int
}

func Constructor() MyLinkedList {
head := &node{}
tail := &node{}
head.next = tail
tail.prev = head
return MyLinkedList{head, tail, 0}
}

func (l *MyLinkedList) Get(index int) int {
if index < 0 || index >= l.size {
return -1
}
var curr *node
if index+1 < l.size-index {
curr = l.head
for i := 0; i <= index; i++ {
curr = curr.next
}
} else {
curr = l.tail
for i := 0; i < l.size-index; i++ {
curr = curr.prev
}
}
return curr.val
}

func (l *MyLinkedList) AddAtHead(val int) {
l.AddAtIndex(0, val)
}

func (l *MyLinkedList) AddAtTail(val int) {
l.AddAtIndex(l.size, val)
}

func (l *MyLinkedList) AddAtIndex(index, val int) {
if index > l.size {
return
}
index = max(0, index)
var pred, succ *node
if index < l.size-index {
pred = l.head
for i := 0; i < index; i++ {
pred = pred.next
}
succ = pred.next
} else {
succ = l.tail
for i := 0; i < l.size-index; i++ {
succ = succ.prev
}
pred = succ.prev
}
l.size++
toAdd := &node{val, succ, pred}
pred.next = toAdd
succ.prev = toAdd
}

func (l *MyLinkedList) DeleteAtIndex(index int) {
if index < 0 || index >= l.size {
return
}
var pred, succ *node
if index < l.size-index {
pred = l.head
for i := 0; i < index; i++ {
pred = pred.next
}
succ = pred.next.next
} else {
succ = l.tail
for i := 0; i < l.size-index-1; i++ {
succ = succ.prev
}
pred = succ.prev.prev
}
l.size--
pred.next = succ
succ.prev = pred
}

func max(a, b int) int {
if b > a {
return b
}
return a
}

复杂度分析

  • 时间复杂度:初始化消耗 O(1),get 消耗 O(\textit{index}),addAtHead 消耗 O(1),addAtTail 消耗 O(1),addAtIndex 消耗 O(\textit{index})。

  • 空间复杂度:所有函数单次调用的空间复杂度均为 O(1),总体空间复杂度为 O(n),其中 n 为 addAtHead,addAtTail 和 addAtIndex 调用次数之和。

 Comments
On this page
0707-设计链表