python实现链表(单向链表以及双向链表)
单向链表也是一种非常基本的数据结构,跟列表比较起来,它的内存不连续,在实际应用中场景还是多于列表的,列表之所以使用的场景多于链表无外乎以下几个原因:
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)。