线性表
定义:
线性表的定义是描述其逻辑结构,而通常会在线性表上进行的查找、插入、删除等操作。
线性表作为一种基本的数据结构类型,在计算机存储器中映象(表示)一般有两种形式,一种是顺序映象,一种是链式映象。
线性表的顺序存储
若将线性表L=(a0,a1,…an+1)中的各个元素一次存储于计算机一片连续的存储空间,这种机制表示为线性表的顺序存储结构。
特点:
逻辑上相邻的元素 ai,ai+1,其存储位置也是相邻的;
存储密度高,方便对数据遍历查找。
对表的插入和删除等运算的效率较差。
程序实现
在Python中,list存放于一片单一连续的内存块,故可借助于列表类型来描述线性表的顺序存储结构,而且列表本身就提供了丰富的接口满足这种数据结构的运算。
线性表链式存储
特点:
-
逻辑上相邻的元素 ai,ai+1,其存储位置也不一定相邻。
-
存储稀疏,必须开辟整块存储空间。
-
对表的插入和删除等运算的效率较高。
-
逻辑结构复杂。
程序实现:
创建明为link_list.py的脚本,主要用于编写链式结构的线性表,并将其接口也做好封装
#创建节点类
class Node:
"""
思路:将自定义的类视为节点的生成的类,实例对象中包含数据部分和指向下一个节点的next
"""
def __init__(self, val, next=None):
self.val = val
self.next = next
class LinkList():
"""
思路:单链表类,生成对象可以进行增删改查操作
具体操作通过调用具体方法完成。
"""
def __init__(self):
"""
初始化链表,标记一个链表的开端,以便于获取后续的节点。
"""
self.head = Node(None)
# 通过list_为来拿表添加一组节点
def init_list(self, list_):
p = self.head # p作为移动变量
for item in list_:
p.next = Node(item)
p = p.next
# 遍历链表
def show(self):
p = self.head.next
while p is not None:
print(p.val)
p = p.next # 向后移动一个
# 判断链表为空
def is_empty(self):
if self.head.next is None:
return True
else:
return False
# 清空链表
def clear(self):
self.head.next = None
# 尾部插入
def append(self, val):
p = self.head
while p.next is not None:
p = p.next
p.next = Node(val)
# 头部插入
def head_insert(self, val):
node = Node(val)
node.next = self.head.next
self.head.next = node
# 插入指定位置
def insert(self, index, val):
p = self.head
for i in range(index):
if p.next is None:
break
p = p.next
node = Node(val)
node.next = p.next
p.next = node
# 删除节点
def delete(self, x):
p = self.head
while p.next and p.next.val != x:
p = p.next
if p.next is None:
raise ValueError(" x is not in linklist")
else:
p.next = p.next.next
# 获取某个索引的值,传入节点位置,获取节点值
def get_index(self, index):
p = self.head.next
for i in range(index):
if p.next is None:
raise IndexError("index out of range")
p = p.next
return p.val
测试
from link_list import *
import time
# l = range(999999)
l = [i for i in range(999999)]
# 链表初始化
link = LinkList()
# 链表插入
link.init_list(l)
# 开始计时
tm = time.time()
# for i in l:
# print(i) # 3.307s 列表
# link.show() # 4.61s 单链表
# l.append(8899) # 列表尾部插入 2.86* 10-6
# link.append(8899) # 链表尾部插入 0.0534
# l.insert(0, 8899) # 列表头部插入,0.00392
# link.head_insert(8899) # 链表头部插入 4.76*10-6
# l.insert(100, 2344) # 列表插入到指定位置数据, 0.0037
# link.insert(300000, 2344) # 0.021
# l.remove(200) # 按照值进行删除 0.0058
# link.delete(850218) # 按照值进行删除 0.085
# print(l[10]) # 按照索引获取值,1.88
# print(link.get_index(10)) # 按照索引获取值,2.69*10-5
# 计时结束
print("time:", time.time() - tm)
'''
总结:
1. 数据初始化输出,列表的速度最快,即线性表的顺序结构查询速度高。
2. 数据尾部插入,列表速度最快,即线性表的顺序结构。
3. 数据头部插入,链表的插入最快,不需要遍历,列表插入时,需要把后续数据全部重构。
4. 插入到指定指定位置时,只有特殊的头部或尾部才有明显的时间差,其他位置时间差相差不大。
'''
练习题
'''
现有两个有序的列表,请使用单链表方式将其进行合并,合并后的数据仍然是有序数据.
'''
from link_list import *
l1 = LinkList()
l2 = LinkList()
l1.init_list([2, 3, 5, 9, 13, 15])
l2.init_list([1, 4, 6, 7, 8, 10, 11, 12, 14])
def merge(l1, l2):
p = l1.head
q = l2.head.next
while p.next is not None:
if p.next.val < q.val:
p = p.next
else:
tmp = p.next
p.next = q
p = p.next
q = tmp
p.next = q
merge(l1, l2)
l1.show()