python 单向链表_01_单向链表的基本用法[Python]

1. 数据结构与算法

想起班级拍毕业合照的时候,摄影师让喊口号,于是乎大家从C、C++、Java、Python、Go、R,一直喊了个遍。程序语言有很多,但数据结构和算法的思维是根本所在。

程序 = 数据结构 + 算法

总结:算法是为了解决实际问题而设计的,数据结构是算法需要处理的问题载体。数据结构只是静态的描述了数据元素之间的关系。高效的程序需要在数据结构的基础上设计和选择算法。

2. 时间复杂度与Python内置函数

时间复杂度的计算:

基本操作,即只有常数项,认为其时间复杂度为O(1)

顺序结构,时间复杂度按加法进行计算

循环结构,时间复杂度按乘法进行计算

分支结构,时间复杂度取最大值

判断一个算法的效率时,往往只需要关注操作数量的最高次项,其它次要项和常数项可以忽略

在没有特殊说明时,我们所分析的算法的时间复杂度都是指最坏时间复杂度

Python内置时间函数:timeIt模块

timeit模块可以用来测试一小段Python代码的执行速度。

class timeit.Timer(stmt='pass', setup='pass', timer=)

Timer是测量小段代码执行速度的类。

stmt参数是要测试的代码语句(statment);

setup参数是运行代码时需要的设置;

timer参数是一个定时器函数,与平台有关。

timeit.Timer.timeit(number=1000000)

Timer类中测试语句执行速度的对象方法。number参数是测试代码时的测试次数,

默认为1000000次。方法返回执行代码的平均耗时,一个float类型的秒数。

List操作测试:

def test1():

l = []

for i in range(1000):

l = l + [i]

def test2():

l = []

for i in range(1000):

l.append(i)

def test3():

l = [i for i in range(1000)]

def test4():

l = list(range(1000))

from timeit import Timer

t1 = Timer("test1()", "from __main__ import test1")

print("concat ",t1.timeit(number=1000), "seconds")

t2 = Timer("test2()", "from __main__ import test2")

print("append ",t2.timeit(number=1000), "seconds")

t3 = Timer("test3()", "from __main__ import test3")

print("comprehension ",t3.timeit(number=1000), "seconds")

t4 = Timer("test4()", "from __main__ import test4")

print("list range ",t4.timeit(number=1000), "seconds")

# ('concat ', 1.7890608310699463, 'seconds')

# ('append ', 0.13796091079711914, 'seconds')

# ('comprehension ', 0.05671119689941406, 'seconds')

# ('list range ', 0.014147043228149414, 'seconds')

3. 单向链表

单向链表也叫单链表,是链表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。

单向链表结构

表元素域elem用来存放具体的数据。

链接域next用来存放下一个节点的位置(python中的标识)

变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。

单链表的操作

is_empty() 链表是否为空

length() 链表长度

travel() 遍历整个链表

add(item) 链表头部添加元素

append(item) 链表尾部添加元素

insert(pos, item) 指定位置添加元素

remove(item) 删除节点

search(item) 查找节点是否存在

节点的实现

class SingleNode(object):

"""单链表的结点"""

def __init__(self,elem):

# _item存放数据元素

self.elem = elem

# _next是下一个节点的标识

self.next = None

单链表的实现

class SingleLinkList(object):

"""单链表"""

def __init__(self):

self._head = None

def is_empty(self):

"""判断链表是否为空"""

return self._head == None

def length(self):

"""链表长度"""

# cur初始时指向头节点

cur = self._head

count = 0

# 尾节点指向None,当未到达尾部时

while cur != None:

count += 1

# 将cur后移一个节点

cur = cur.next

return count

def travel(self):

"""遍历链表"""

cur = self._head

while cur != None:

print cur.item,

cur = cur.next

print ""

头部添加元素

add(self,elem)

def add(self, item):

"""头部添加元素"""

# 先创建一个保存item值的节点

node = SingleNode(item)

# 将新节点的链接域next指向头节点,即_head指向的位置

node.next = self._head

# 将链表的头_head指向新节点

self._head = node

尾部添加元素

def append(self, item):

"""尾部添加元素"""

node = SingleNode(item)

# 先判断链表是否为空,若是空链表,则将_head指向新节点

if self.is_empty():

self._head = node

# 若不为空,则找到尾部,将尾节点的next指向新节点

else:

cur = self._head

while cur.next != None:

cur = cur.next

cur.next = node

指定位置添加元素

insert(self,pos,elem)

def insert(self, pos, item):

"""指定位置添加元素"""

# 若指定位置pos为第一个元素之前,则执行头部插入

if pos <= 0:

self.add(item)

# 若指定位置超过链表尾部,则执行尾部插入

elif pos > (self.length()-1):

self.append(item)

# 找到指定位置

else:

node = SingleNode(item)

count = 0

# pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置

pre = self._head

while count < (pos-1):

count += 1

pre = pre.next

# 先将新节点node的next指向插入位置的节点

node.next = pre.next

# 将插入位置的前一个节点的next指向新节点

pre.next = node

删除节点

delete(self,elem)

def delete(self,item):

"""删除节点"""

cur = self._head

pre = None

while cur != None:

# 找到了指定元素

if cur.item == item:

# 如果第一个就是删除的节点

if not pre:

# 将头指针指向头节点的后一个节点

self._head = cur.next

else:

# 将删除位置前一个节点的next指向删除位置的后一个节点

pre.next = cur.next

break

else:

# 继续按链表后移节点

pre = cur

cur = cur.next

查找节点是否存在

def search(self,item):

"""链表查找节点是否存在,并返回True或者False"""

cur = self._head

while cur != None:

if cur.item == item:

return True

cur = cur.next

return False

测试

if __name__ == "__main__":

ls=single_linkList(Node(1))

ls.add(0)

ls.append(3)

# ls.travel()

ls.insert(2,2)

ls.travel()

ls.insert(-1, 2)

ls.travel()

print("the lenth is :%d"%(ls.length()))

print("the linkList is empty: %d"%(ls.is_empty()))

ls.delete(1)

ls.travel()

Tips:

链表失去了顺序表随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大,但对存储空间的使用要相对灵活。

链表的主要耗时操作是遍历查找,删除和插入操作本身的复杂度是O(1)。顺序表查找很快,主要耗时的操作是拷贝覆盖。因为除了目标元素在尾部的特殊情况,顺序表进行插入和删除时需要对操作点之后的所有元素进行前后移位操作,只能通过拷贝和覆盖的方法进行。

4. 参考

传智播客黑马程序员Python数据结构课程讲义

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值