Skip to content

Commit 5eaa67c

Browse files
committed
设计链表
设计链表
1 parent 98d0619 commit 5eaa67c

File tree

7 files changed

+143
-33
lines changed

7 files changed

+143
-33
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
|[Python爬虫](./spiders/main.md)|python爬虫基础库requests,beautifulsoup,xpath,selenium,代理池,部分网站爬虫等......|
88
|[计算机网络基础](./network_protocol/main.md)|网络基础知识,tcp/ip协议与http协议等......|
99
|[LeetCode-数组](./leetcode_array/main.md)|leetcode数组类算法刷题。|
10-
|[LeetCode-栈](./leetcode_stack/main.md)|leetcode栈类算法刷题。|
1110
|[LeetCode-链表](./leetcode_linked_list/main.md)|leetcode链表类算法刷题。|
11+
|[LeetCode-栈](./leetcode_stack/main.md)|leetcode栈类算法刷题。|
1212
|[LeetCode-树](./leetcode_tree/main.md)|leetcode树类算法刷题。|
1313
|[Django学习](./django_note/main.md)|Django学习笔记。|
1414
|[其他](./others/main.md)|redis,kafka,ZeroMQ等|

leetcode_array/main.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
**连续内存空间保证了数组的“随机访问”特性,根据下标随机访问数组中元素的时间复杂度为O(1),同样为了保证内存空间的连续,插入与删除元素都会导致大量元素被迫移动,影响效率,时间复杂度为O(n)。**
66

7-
**数组,链表,队列,栈都是线性表结构,二叉树,堆,图属于非线性结构。**
7+
**数组,链表,队列,栈都是线性表结构(线性表结构可分为顺序存储结构和链式存储结构),二叉树,堆,图属于非线性结构。**
88

99
## 2.题目
1010
* [搜索插入位置(二分查找)](搜索插入位置.md)

leetcode_linked_list/main.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
1-
## LeetCode链表
2-
1. [合并两个有序链表*](合并两个有序链表.md)
1+
# LeetCode链表
2+
## 1.定义
3+
**链表是一种物理存储单元上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现。**
4+
5+
**链表中每个元素称为节点,节点包括两部分,一是存储数据元素的数据域,一是存储下一个节点地址的指针域。**
6+
7+
**由于不必按照顺序存储,链表插入和删除元素的时间复杂度O(1),查找元素的时间复杂度O(n)**
38

9+
## 2.数组与链表比较、
10+
* 从逻辑结构方面,两者都属于线性表,数组是顺序存储结构的线性表,链表是链式存储结构的线性表。
11+
* 从物理内存方面,数组占用的是一段连续的内存区,链表在内存中是非连续的,分散的,是通过指针实现逻辑上的线性表。
12+
* 对于访问,由于数组在内存上是连续的,所以支持“随机访问”,时间复杂度O(1),而链表是非连续的内存空间,只能通过“顺序访问”,时间复杂度O(n)
13+
* 对于插入/删除元素,数组的时间复杂度O(n),链表的时间复杂度O(1)
14+
15+
## 3.题目
16+
* [移除链表元素(虚拟头结点)](移除链表元素.md)
17+
* [设计链表(虚拟头结点)](设计链表.md)
18+
19+
<!--
20+
1. [合并两个有序链表*](合并两个有序链表.md)
421
2. [删除排序链表中的重复元素(单个指针)](删除排序链表中的重复元素.md)
522
3. [环形链表](环形链表.md)
623
4. [相交链表](相交链表.md)
@@ -10,3 +27,4 @@
1027
8. [删除链表中的节点](删除链表中的节点.md)
1128
9. [链表的中间结点](链表的中间结点.md)
1229
10. [二进制链表转整数](二进制链表转整数.md)
30+
-->
Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,42 @@
1-
## 移除链表元素
1+
# 203.移除链表元素
22
删除链表中等于给定值 val 的所有节点。
33
#### 示例
44
```python
55
输入: 1->2->6->3->4->5->6, val = 6
66
输出: 1->2->3->4->5
77
```
88

9-
#### 代码
10-
哨兵节点广泛应用于树和链表中,如伪头、伪尾、标记等,它们是纯功能的,通常不保存任何数据,其主要目的是使链表标准化,如使链表永不为空、永不无头、简化插入和删除。
9+
#### 分析
10+
* 添加虚拟头结点,然后从头部开始遍历链表
11+
* 如果当前节点下一个节点值为目标值,就将当前节点的下一个节点指向下下个节点
12+
* 如果当前节点的下一个节点不是目标值,就将下一个节点作为当前节点
1113

12-
```python
13-
# 原链表
14-
1->2->6->3->4->5->6
15-
# 添加哨兵节点
16-
0->1->2->6->3->4->5->6
14+
![](../pic/leetcode_linked_list/203_1.png)
15+
![](../pic/leetcode_linked_list/203_2.png)
1716

18-
# 当前节点指向1,前继节点指向哨兵节点0
19-
# 如果当前节点为要删除节点,前继节点.next = 当前节点.next,当前节点后移
20-
# 如果当前节点不是要删除的节点,前继节点 = 当前节点,当前节点后移
17+
```python
18+
class ListNode:
19+
def __init__(self, x):
20+
self.val = x
21+
self.next = None
2122

22-
```
23+
def __str__(self):
24+
vals = [str(self.val)]
25+
next_node = self.next
26+
while next_node:
27+
vals.append(str(next_node.val))
28+
next_node = next_node.next
29+
return '->'.join(vals)
2330

24-
* 初始化哨兵节点为 ListNode(0) 且设置 sentinel.next = head。
25-
* 初始化两个指针 curr 和 prev 指向当前节点和前继节点。
26-
* 当前节点不为None时,比较当前节点与目标值,如果相等,则prev.next = curr.next;如果不相等prev = curr
27-
* 遍历下一个元素:curr = curr.next
2831

29-
```python
3032
def removeElements(head, val):
31-
sentinel = ListNode(0)
32-
sentinel.next = head
33-
34-
prev = sentinel # 前继节点
35-
cur = head # 当前节点
36-
37-
while cur:
38-
if cur.val == val:
39-
prev.next = cur.next
33+
start = ListNode(0) # 虚拟头结点
34+
cur_node = start
35+
cur_node.next = head
36+
while cur_node.next:
37+
if cur_node.next.val == val:
38+
cur_node.next = cur_node.next.next
4039
else:
41-
prev = cur
42-
cur = cur.next
43-
return sentinel.next
40+
cur_node = cur_node.next
41+
return start.next
4442
```
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# 707.设计链表
2+
## 题目
3+
```
4+
在链表类中实现这些功能:
5+
get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
6+
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
7+
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
8+
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val  的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
9+
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
10+
```
11+
12+
## 分析
13+
* 链表初始化两个属性,一个是链表的大小self.size,一个是虚拟头结点self.head
14+
* 需要先考虑实现addAtIndex(index,val)方法
15+
* addAtHead(val)其实就是addAtIndex(0,val)
16+
* addAtTail(val)其实就是addAtIndex(self.size,val)
17+
18+
#### 如何实现addAtIndex(index,val)
19+
* 找到插入位置的前一个节点,如果是头部,那前一个节点就是虚拟头结点
20+
* deleteAtIndex(index)和插入一样,都是要找到目标节点的前一个节点
21+
22+
## 代码
23+
```python
24+
25+
class ListNode:
26+
def __init__(self, x):
27+
self.val = x
28+
self.next = None
29+
30+
def __str__(self):
31+
vals = [str(self.val)]
32+
next_node = self.next
33+
while next_node:
34+
vals.append(str(next_node.val))
35+
next_node = next_node.next
36+
return '->'.join(vals)
37+
38+
39+
class MyLinkedList:
40+
41+
def __init__(self):
42+
self.size = 0
43+
self.head = ListNode(0)
44+
45+
def get(self, index: int) -> int:
46+
# 如果索引无效,返回-1
47+
if index < 0 or index >= self.size:
48+
return -1
49+
curr = self.head
50+
for _ in range(index+1):
51+
curr = curr.next
52+
return curr.val
53+
54+
def addAtHead(self, val: int) -> None:
55+
self.addAtIndex(0, val)
56+
57+
def addAtTail(self, val: int) -> None:
58+
self.addAtIndex(self.size, val)
59+
60+
def addAtIndex(self, index: int, val: int) -> None:
61+
# 在链表的第index节点添加值为val的节点
62+
# 如果index等于链表长度,添加在尾部
63+
# 如果index大于链表长度,不添加
64+
# 如果index小于0,添加在首部
65+
if index > self.size:
66+
return
67+
if index < 0:
68+
index = 0
69+
self.size += 1
70+
# 找到要插入位置的前一个节点
71+
pred = self.head
72+
for _ in range(index):
73+
pred = pred.next
74+
75+
# 要添加的节点
76+
to_add = ListNode(val)
77+
# 插入
78+
to_add.next = pred.next
79+
pred.next = to_add
80+
81+
def deleteAtIndex(self, index: int) -> None:
82+
# 如果index有效,删除链表中第index个节点
83+
if index < 0 or index >= self.size:
84+
return
85+
self.size -= 1
86+
# 找到要删除的节点的前一个节点
87+
pred = self.head
88+
for _ in range(index):
89+
pred = pred.next
90+
91+
# 删除
92+
pred.next = pred.next.next
93+
94+
```

pic/leetcode_linked_list/203_1.png

37.8 KB
Loading

pic/leetcode_linked_list/203_2.png

23.9 KB
Loading

0 commit comments

Comments
 (0)