本文最后更新于:2024年7月6日 早上
1. 线性表简介 线性表是一种线性结构,它是由零个或多个数据元素构成的有限序列 。线性表的特征是在一个序列中,除了头尾元素,每个元素都有且只有一个直接前驱,有且只有一个直接后继,而序列头元素没有直接前驱,序列尾元素没有直接后继。
数据结构中常见的线性结构有数组、单链表、双链表、循环链表等。线性表中的元素为某种相同 的抽象数据类型。可以是C语言的内置类型或结构体,也可以是C++自定义类型。
2. 数组 数组在实际的物理内存上也是连续存储的,数组有上界和下界。C语言中定义一个数组:
数组下标是从0开始的,a[0]对应第一个元素。其中,a[0]称为数组a的下界,a[6]称为数组a的上届。超过这个范围的下标使用数组,将造成数组越界错误 。 数组的特点是:数据连续,支持快速随机访问。 数组分为固定数组与动态数组。其中固定数组的大小必须在编译时就能够确认,动态数组允许在运行时申请数组内存。复杂点的数组是多维数组,多维数组实际上也是通过一维数组来实现的。在C语言中,可以通过malloc来分配动态数组,C++使用new。另外,C++的标准模板库提供了动态数组类型vector以及内置有固定数组类型array。
Python中list可以被认为是封装好的数组。
3. 单向链表 单向链表是链表的一种。链表由节点所构成,节点内含一个指向下一个节点的指针,节点依次链接成为链表。因此,链表这种数据结构通常在物理内存上是不连续的。链表的通常含有一个头节点,头节点不存放实际的值,它含有一个指针,指向存放元素的第一个节点。
show me the code
1 2 3 4 5 6 7 8 9 10 11 12 class Node (): """ 单链表中的节点应该具有两个属性:val 和 next。 val 是当前节点的值, next 是指向下一个节点的指针/引用。 """ def __init__ (self, value ): self.val = value self.next = None
设计链表的实现 您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val
和 next
。val
是当前节点的值,next
是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev
以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。
在链表类中实现这些功能:
get(index):获取链表中第 index
个节点的值。如果索引无效,则返回-1
。
addAtHead(val):在链表的第一个元素之前添加一个值为 val
的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val
的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index
个节点之前添加值为 val
的节点。如果 index
等于链表的长度,则该节点将附加到链表的末尾。如果 index
大于链表长度,则不会插入节点。
deleteAtIndex(index):如果索引 index
有效,则删除链表中的第 index
个节点。
show me the code
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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 """ @Author : Young @Email : [email protected] @site : http://www.cnblogs.com/huang-yc/ @File : linked_list2.py @version : 1.0 @Time : 2019/4/5 11:06 Description about this file: """ class Node (): """ 单链表中的节点应该具有两个属性:val 和 next。 val 是当前节点的值, next 是指向下一个节点的指针/引用。 """ def __init__ (self, value ): self.val = value self.next = None class SingleLinkList (): def __init__ (self, node=None ): self._head = node def is_empty (self ): if self._head is None : return True else : return False def get (self, index: int ) -> int : """ 获取链表中第 index 个节点的值。如果索引无效,则返回-1 :param index: 索引值 :return: """ if self._head is None : return -1 cur = self._head for i in range (index): if cur.next is None : return -1 cur = cur.next return cur.val def length (self ): """ cur游标,用来移动遍历节点 count用来计数 :return: 返回链表的长度 """ cur = self._head count = 0 while cur is not None : count += 1 cur = cur.next return count def travel (self ): """ 遍历整个链表 :return: """ cur = self._head while cur is not None : print (cur.elem, end=' ' ) cur = cur.next def add_at_head (self, val: int ) -> None : """ 在头部添加一个节点 :param val: :return: None """ node = Node(val) if self._head is None : self._head = node else : node.next = self._head self._head = node def add_at_tail (self, val: int ) -> None or int : """ 在尾部添加一个节点 :param item: :return: """ node = Node(val) if self._head is None : self._head = node else : cur = self._head while cur.next is not None : cur = cur.next cur.next = node def add_at_index (self, index: int , val: int ) -> None : """ 在指定位置pos添加节点 pos从0开始 :param index: :param val: :return: """ if index <= 0 : self.add_at_head(val) elif index >= self.length(): self.add_at_tail(val) else : pre = self._head count = 0 node = Node(val) while count < (index - 1 ): count += 1 pre = pre.next node.next = pre.next pre.next = node def delete_at_index (self, index: int ) -> None or int : """ 如果索引 index 有效,则删除链表中的第 index 个节点。 :param index: 对应的索引值 :return: -1表示为异常 """ pre = None cur = self._head if index is 0 : self._head = None for i in range (index): if cur.next is None : return -1 pre = cur cur = pre.next else : pre.next = cur.next def search (self, val: int ) -> True or False : """ 查找节点是否存在 :param val: 节点的val值 :return: """ cur = self._head while cur is not None : if cur.val == val: return True else : cur = cur.next return False if __name__ == '__main__' : obj = SingleLinkList() obj.add_at_head(1 ) obj.add_at_tail(3 ) obj.add_at_index(1 , 2 ) obj.travel() obj.delete_at_index(1 ) obj.travel()
链表与顺序表的对比 链表失去了顺序表随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大,但对存储空间的使用要相对灵活。
链表与顺序表的各种操作复杂度如下所示:
操作
链表
顺序表
访问元素
O(n)
O(1)
在头部插入/删除
O(1)
O(n)
在尾部插入/删除
O(n)
O(1)
在中间插入/删除
O(n)
O(n)
参考资料
https://www.cnblogs.com/QG-whz/p/5170147.html
https://blog.csdn.net/weixin_39881922/article/details/80470896
https://leetcode-cn.com/explore/learn/card/linked-list/193/singly-linked-list/741/