Python数据结构与算法—线性表
定义
线性表的定义是描述其逻辑结构,而通常会在线性表上进行的查找、插入、删除等操作。
线性表作为一种基本的数据结构类型,在计算机存储器中的映象(或表示)一般有两种形式,一种是顺序映象,一种是链式映象。
线性表的顺序存储
1.定义:若将线性表L=(a0,a1, ……,an-1)中的各元素依次存储于计算机一片连续的存储空间,这种机制表示为线性表的顺序存储结构。
2.特点:
- 逻辑上相邻的元素 ai, ai+1,其存储位置也是相邻的;
- 存储密度高,方便对数据的遍历查找。
- 对表的插入和删除等运算的效率较差。
3.程序实现
在Python中,list存放于一片单一连续的内存块,故可借助于列表类型来描述线性表的顺序存储结构,而且列表本身就提供了丰富的接口满足这种数据结构的运算。
1 L = [1,2,3,4] 2 L.append(10) #尾部增加元素 3 #[1, 2, 3, 4, 10] 4 5 L.insert(1,20) #插入元素 6 #[1, 20, 2, 3, 4, 10] 7 8 L.remove(3) #删除元素 9 #[1, 20, 2, 4, 10] 10 11 L[4] = 30 #修改 12 #[1, 20, 2, 4, 30] 13 14 L.index(2) #查找 15 #2
线性表的链式存储
1.定义:将线性表L=(a0,a1,……,an-1)中各元素分布在存储器的不同存储块,称为结点,每个结点(尾节点除外)中都持有一个指向下一个节点的引用,这样所得到的存储结构为链表结构。
2.特点
- 逻辑上相邻的元素 ai, ai+1,其存储位置也不一定相邻;
- 存储稀疏,不必开辟整块存储空间。
- 对表的插入和删除等运算的效率较高。
- 逻辑结构复杂,不利于遍历。
3.程序实现
1 """ 2 linklist.py 链表程序实现 3 重点代码 4 5 思路分析 6 1. 创建节点类,生成节点对象 7 包含数据和下一个节点的引用 8 2. 链表类,生成链表对象 9 可以对链表进行数据操作 10 """ 11 12 13 class Node(): 14 """ 15 一个节点里面包含两个数据,一个是当前的数据,一个是指向下一个数据的next, 16 当next数据为None时,次节点为最后一个节点 17 """ 18 19 def __init__(self, data, next=None): 20 self.data = data 21 self.next = next 22 23 24 class Linklist(): 25 def __init__(self): 26 "生成一个头节点,头结点为head,假设当前的Node是空值" 27 self.head = Node(None) 28 29 # 初始添加一组链表节点 30 def linklist(self, list_): 31 # 设p为头节点 32 p = self.head 33 # 循环链表,链表的每一个值都赋值给p.next 34 for i in list_: 35 p.next = Node(i) 36 # 每一次循环 p.next重新赋值为p 37 p = p.next 38 39 # 遍历链表 40 def shou_link(self): 41 # 设p为第一个节点 (链表中头节点和第一个节点是不同的) 42 # 如果这里把p设为头节点的话,那while就要从第一节点开始 43 p = self.head.next 44 # 如果p.next为空值,此时的p.next是链表中的最后一个节点, 45 while p is not None: 46 # p.data是本次节点的值,循环打印本次的节点的值 47 print(p.data, end=" ") 48 # 每一次循环 p.next重新赋值为p 49 p = p.next 50 print() 51 52 # 获取链表的长度 53 def get_lenght(self): 54 p = self.head 55 n = 0 56 while p.next is not None: 57 n += 1 58 p = p.next 59 return n 60 61 # 判断链表是否为空 62 def empty(self): 63 # 如果链表的长度为0,那链表自然是空的 64 if self.get_lenght() == 0: 65 return True 66 else: 67 return False 68 69 # 清空链表 70 def clear(self): 71 # 第一个节点为空值,那就后面的几个节点就断开了,也就相当于清空了 72 self.head.next = None 73 74 # 尾部插入节点 75 def add_link(self, data): 76 # 生成一个新的节点,把这个节点插到尾部 77 # node是节点 data是节点的值 78 node = Node(data) 79 p = self.head 80 # 循环出最后一个节点 81 while p.next is not None: 82 p = p.next 83 # 循环完最后一个p为最后一个节点,将最后一个节点用next连接node, node为链表的最后一个节点 84 p.next = node 85 86 # 选择位置插入节点 87 # 思想:先将新节点的next连接后一个节点,再将前一个节点的next连接新节点 88 def insert(self, index, data): 89 # 先判断 下标index的位置,要求下标不能小于0和大于链表的长度 90 # 如果超出范围,人工报错 91 if index < 0 or index > self.get_lenght(): 92 raise IndexError("index out of range") 93 p = self.head 94 # 定义p移动到插入位置的前一个 95 for i in range(index): # index从0开始 96 # 假如index=0,p=p.next 97 # 假如index=1,p=p.next.next 98 # 假如index=2,p=p.next.next.next 以此类推 99 p = p.next 100 node = Node(data) # 生成一个新的节点 101 # 将node插入链表p的后面 102 # node的前一个节点p 后一个节点p.next 103 node.next = p.next 104 p.next = node 105 106 # 删除节点 107 # 思想:前一个节点的next 连接到删除节点的后一个节点 108 def del_node(self, data): 109 p = self.head 110 # 查找删除节点的值 111 while p.next and p.next.data != data: 112 p = p.next 113 # 如果循环到最后以为还没找到,说明删除的值不在链表中 114 if p.next is None: 115 raise ValueError("value is error") 116 else: 117 #跨过删除的节点,连接删除节点的后面节点 118 p.next = p.next.next 119 120 # 通过下标,获取节点的值 121 def get_data(self, index): 122 if index < 0 or index > self.get_lenght(): 123 raise IndexError("index out of range") 124 # p为第一个节点 125 p = self.head.next 126 127 for i in range(index): 128 # 同插入节点 129 p = p.next 130 return p.data 131 132 133 print("-----------测试--------------") 134 if __name__ == '__main__': 135 list = Linklist() 136 l = [1, 2, 3, 4, 5] 137 list.linklist(l) 138 list.shou_link() # 1 2 3 4 5 139 print(list.get_lenght()) # 5 140 print(list.empty()) # False 141 list.add_link(6) 142 list.shou_link() # 1 2 3 4 5 6 143 list.insert(3, 22) 144 list.shou_link() # 1 2 3 22 4 5 6 145 list.del_node(5) 146 list.shou_link() # 1 2 3 22 4 6 147 print(list.get_data(2)) # 3 148 list.clear()