单向链表也是一种非常基本的数据结构,跟列表比较起来,它的内存不连续,在实际应用中场景还是多于列表的,列表之所以使用的场景多于链表无外乎以下几个原因:
1、列表是python内置的数据结构,可以直接使用;链表需要我们自己去设计
2、列表作为内置数据类型,为我们隐藏了实现细节,只是暴露了几个操作它的api(append、remove、pop、[start:stop]等),我们不用去关心底层实现,只关注业务即可;链表每个操作方法需要我们自己去设计
3、数据量比较少的话,列表的内存开销还是要小于链表的,python的链表元素其实是一个个实例化的对象,一般来说内存开销是大于列表的(内存开销测试具体没试验过,个人臆测)
需要自己去设计实现,这个对于python开发者来说就比较难受了,一般都会倾向于直接使用列表而不使用数组。
但是链表也有链表的好处
1、对于内存以及程序响应都比较好,对于python程序来说,声明一个列表,多数情况下都是往里面添加元素的多,这就需要这个列表需要不断地申请扩大内存,不断扩充总会到达边界,这时python就会创建一个链表去链接另外一片比较大的连续内存,这不是一个好的编程习惯,很容易发生内存溢出以及内存泄漏,再者删除指定位置元素还涉及数据元素下标更新的处理,会增加程序的响应时间,顺序添加时间响应还好,要是从头开始插入的话,时间复杂度是O(N2)。
import time
lst1 = list()
lst2 = list()
def cal_time(func):
def wrapper(*args, **kwargs):
t1 = time.time()
result = func(*args, **kwargs)
t2 = time.time()
print("%s running time: %s secs." % (func.__name__, t2 - t1))
return result
return wrapper
# O(n2)
def append_data_from_head(num):
lst1.insert(0, num)
# o(n)
def append_data_from_tail(num):
lst1.append(num)
@cal_time
def get_result(times):
for el in range(times):
append_data_from_head(el)
@cal_time
def get_result1(times):
for el in range(times):
append_data_from_tail(el)
get_result(10000)
get_result1(10000)
1000个数的时间如下
1万个数的时间就成了下面的图(响应时间4秒,也就是比如客户添加一个宝贝到购物车,4分钟之后显示添加成功,估计会直接卸载这个应用)
而链表的更新以及插入数据的时间复杂度是O(N),其时间和append的时间差不多
2、减少内存碎片产生的可能性,列表是申请的连续内存,如果存储的对象大小不一致,当删除一个元素,下一个元素填补就可能存在使用不了的内存碎片
废话不再多说,直接上代码:
1、单向链表以及增删改查方法
1 # 初始化节点,添加值以及指针属性
2 class Node:
3 def __init__(self, value, next_=None):
4 self.value = value
5 self.next_ = next_
6
7 # 可以直接获取到指定节点的值
8 def get_data(self):
9 return self.value
10
11 # 直接设置获取到的节点的值
12 def set_new_data(self, new_value):
13 self.value = new_value
14
15
16 # 定义链表的类
17 class LinkList(object):
18 # 初始化头部节点并且初始化长度
19 def __init__(self, head=None):
20 self.head = head
21 if self.head:
22 self.length = 1
23 else:
24 self.length = 0
25
26 # 获取头部节点
27 def get_head(self):
28 return self.head
29
30 # 判断链表是否为空链表
31 def is_empty(self):
32 if not self.length:
33 return True
34 return False
35
36 # 添加新节点
37 def append_node(self, data_or_node):
38 # 判断是否是节点的实例
39 if isinstance(data_or_node, Node):
40 item = data_or_node
41 else:
42 item = Node(data_or_node)
43 # 判断是不是空链表,当然也可以通过is_empty来判断
44 if not self.head:
45 self.head = item
46 self.length += 1
47 else:
48 node = self.head # 头结点始终保持不变
49 # 遍历链表,找到最后一个节点
50 while node.next_:
51 node = node.next_
52 # 找到并且赋值
53 node.next_ = item
54 self.length += 1
55
56 # 删除节点,传入下标
57 def delete_node(self, index):
58 if self.is_empty():
59 print("this link list is empty.")
60 return
61 if index < 0 or index >= self.length:
62 print("error: out of index.")
63 return
64 # 下标为0,直接设置头节点的下一个节点为头部节点同时长度减一
65 if index == 0:
66 self.head = self.head.next_
67 self.length -= 1
68 # 一般的节点,需要找到下标的前一个子节点以及后一个子节点,然后直接连接起来,丢掉下标所在的节点
69 node = self.head
70 pre = self.head
71 # 定位找到下标所在的节点
72 while node.next_ and index:
73 # 先确定前一个子节点,之后是往后找下一个子节点
74 pre = node
75 node = node.next_
76 index -= 1
77 if not index:
78 # 找到了,前一个子节点的下一个指针连接当前节点的下一个节点同时长度减一
79 pre.next_ = node.next_
80 self.length -= 1
81
82 def update_node(self, index, value):
83 if self.is_empty():
84 print("this link list is empty.")
85 return
86 if index < 0 or index >= self.length:
87 print("error: out of index")
88 return
89 node = self.head
90 while node.next_ and index:
91 node = node.next_
92 index -= 1
93 if not index:
94 node.value = value
95
96 def get_node(self, index):
97 if self.is_empty():
98 print("this link list is empty.")
99 return
100 if index < 0 or index >= self.length:
101 print("error: out of index.")
102 node = self.head
103 while node.next_ and index:
104 node = node.next_
105 index -= 1
106 if not index:
107 return node.value
108
109 def get_index(self, value):
110 if self.is_empty():
111 print("this link list is empty.")
112 return
113 node = self.head
114 j = 0
115 while node:
116 if node.value == value:
117 return j
118 else:
119 node = node.next_
120 j += 1
121 if j == self.length:
122 print("%s not found." % value)
123 return
124
125 def insert_node(self, index, data_or_node):
126 if self.is_empty():
127 print("this link list is empty.")
128 return
129 if index < 0 or index >= self.length:
130 print("error: out of index.")
131 return
132 if isinstance(data_or_node, Node):
133 item = data_or_node
134 else:
135 item = Node(data_or_node)
136 if index == 0:
137 item.next_ = self.head
138 self.head = item
139 self.length += 1
140 node = self.head
141 pre = self.head
142 while node.next_ and index:
143 pre = node
144 node = node.next_
145 index -= 1
146 if not index:
147 pre.next_ = item
148 item.next_ = node
149 self.length += 1
150
151 def clear(self):
152 self.head = None
153 self.length = 0
154
155
156 link_list = LinkList()
157 # 新增一个节点
158 link_list.append_node(0)
159 # 获取节点值
160 node_0_val = link_list.get_node(0)
161 print(node_0_val, link_list.length) # 0 1
162 # 获取值为0的数据的位置
163 node_0_index = link_list.get_index(0)
164 print(node_0_index) # 0
165 link_list.append_node(1)
166 link_list.append_node(1)
167 link_list.append_node(4)
168 link_list.append_node(5)
169 print(link_list.length) # 5
170 # 遍历所有数据
171 for el in range(link_list.length):
172 print(link_list.get_node(el)) # 0 1 1 4 5
173
174 # 插入一个数据
175 link_list.insert_node(3, 3)
176 # 遍历所有数据
177 for el in range(link_list.length):
178 print(link_list.get_node(el)) # 0 1 1 3 4 5
179
180 # 修改一个数据
181 link_list.update_node(2, 2)
182 print(">" * 10)
183 for el in range(link_list.length):
184 print(link_list.get_node(el)) # 0 1 2 3 4 5
185
186 # 删除一个节点
187 link_list.delete_node(4)
188 print("<" * 10)
189 for el in range(link_list.length):
190 print(link_list.get_node(el)) # 0 1 2 3 5
2、双向链表以及增删改查方法
1 class Node(object):
2 def __init__(self, value, p=None):
3 self.data = value
4 self.next = p
5 self.prev = p
6
7 def get_data(self):
8 return self.data
9
10 def set_new_data(self, new_value):
11 self.value = new_value
12
13
14 class Linklist(object):
15 def __init__(self, head=None):
16 self.head = head
17 if self.head:
18 self.length = 1
19 else:
20 self.length = 0
21
22 def is_empty(self):
23 if not self.length:
24 return True
25 return False
26
27 def append(self, data_or_node):
28 if isinstance(data_or_node, Node):
29 item = data_or_node
30 else:
31 item = Node(data_or_node)
32 if not self.head:
33 self.head = item
34 self.length += 1
35 else:
36 node = self.head
37 while node.next:
38 node = node.next
39 node.next = item
40 item.prev = node
41 self.length += 1
42
43 def insert(self, index, data_or_node):
44 if self.is_empty():
45 print("this link list is empty.")
46 return
47 if index < 0 or index >= self.length:
48 print("error: out of index")
49 return
50 if isinstance(data_or_node, Node):
51 item = data_or_node
52 else:
53 item = Node(data_or_node)
54 if index == 0:
55 item.next = self.head
56 self.head.prev = item
57 self.head = item
58 self.length += 1
59 node = self.head
60 while node.next and index:
61 node = node.next
62 index -= 1
63 if not index:
64 # 先找到当前节点的前一个节点,之后是先创建前指向当前节点的指针,然后当前节点指向前一个节点的指针
65 pre_node = node.prev
66 pre_node.next = item
67 item.prev = pre_node
68 item.next = node
69 node.prev = item
70 self.length += 1
71 #
72
73 def update_node(self, index, value):
74 if self.is_empty():
75 print("this link list is empty.")
76 return
77 if index < 0 or index >= self.length:
78 print("error: index out of range.")
79 return
80 if index == 0:
81 self.head.set_new_data(value)
82 node = self.head
83 while node.next and index:
84 node = node.next
85 index -= 1
86 if not index:
87 node.set_new_data(value)
88
89 def delete_node(self, index):
90 if self.is_empty():
91 print("this link list is empty.")
92 return
93 if index < 0 or index >= self.length:
94 print("error: index out of range.")
95 return
96 if index == 0:
97 self.head = self.head.next
98 self.head.prev = None
99 self.length -= 1
100 return
101 prev_node = self.head
102 node = self.head
103 while node.next and index:
104 prev_node = node.prev
105 node = node.next
106 index -= 1
107 if not index:
108 # 需要连接两次,分别是当前位置前一个节点连接后面的一个节点,后面的一个节点连接前一个节点,当前节点断了prev和next
109 post_node = node.next
110 prev_node.next = post_node
111 post_node.prev = prev_node
112 node.prev = None
113 node.next = None
114 self.length -= 1
115
116 def get_node(self, index):
117 node = self.head
118 while node.next and index:
119 # print(node.next, index)
120 node = node.next
121 index -= 1
122 print(node.get_data())
123 return node.get_data()
124
125 def get_pre_node(self, index):
126 if index == 0:
127 return
128 else:
129 node = self.head
130 while node.next and index:
131 node = node.next
132 index -= 1
133 if not index:
134 node = node.prev
135 print(node.get_data())
136 return node.get_data()
137
138
139 link_lst = Linklist()
140 link_lst.append(0)
141 link_lst.append(1)
142 link_lst.append(2)
143 link_lst.append(4)
144 link_lst.append(5)
145 link_lst.insert(3, 3)
146 link_lst.get_node(0)
147 link_lst.get_node(1)
148 link_lst.get_node(2)
149 link_lst.get_node(3)
150 link_lst.get_node(4)
151 link_lst.get_node(5)
152
153 print("删除节点")
154 link_lst.delete_node(2)
155
156 link_lst.get_node(0)
157 link_lst.get_node(1)
158 link_lst.get_node(2)
159 link_lst.get_node(3)
160 print(">" * 100)
161 link_lst.get_pre_node(0)
162 print(">" * 10)
163 link_lst.get_pre_node(1)
164 print(">" * 10)
165 link_lst.get_pre_node(2)
166 print(">" * 10)
167 link_lst.get_pre_node(3)
168 print(">" * 10)
待优化项的是尾部新增一个节点的时间复杂度从O(n)简化到O(1)。