线性表
线性表的基本概念
线性表(Linear List)是其组成元素间具有线性关系的一种线性结构,是由
个具有相同数据类型(字符串、整数、浮点数、对象或其他更复杂的信息)的数据元素构成的有限序列,一般表示为:
{a1,a2,a3,a4,a5,…}
i 代表数据元素在线性表中的位序号( 0 <= i < n)
n 是线性表中的元素个数,称为线性表的长度
线性表的两种存储结构
顺序存储结构
优缺点
优点:
1.尾插效率高,便于随机访问
2.cpu缓存利用率高
3.存取速度高效,通过下标来直接存储
缺点:
1.不利于插入和删除操作
2.不可以增长长度
链式存储结构
- 单链表
- 双链表
- 循环列表
优缺点
优点:
1.物理存储单元上非连续,而且采用动态内存分配,能够 有效的分配和利用内存资源
2.节点删除和插入简单,不需要内存空间的重组。
缺点:
1.不能进行索引访问,只能从头结点开始顺序查找
2.数据结构较为复杂,需要大量的 指针操作,容易出错
顺序表
1.初始化顺序表
初始化顺序表时献给顺序表分配内存空间
def _init_(self,max):
"""
初始化
:param max:顺序表的最大容量
"""
self.max = max
self.index = 0
self.data - [None for _ in range(self.max)]
在Python中通常实例对象初始化时会用到__init__方法
例如,下面的代码就创建了一个名叫 my_list 的实例
class MyList:
def __init__(self, max):
self.max = max
self.index = 0
self.data = [None for _ in range(self.max)]
my_list = MyList(10)
2.按下标值查找元素
如何下标值合法,则返回该下标值上的元素,否则抛出异常
def __getitem__(self, index):
if index < 0 or index >= self.index:
raise IndexError('index非法')
else:
return self.data[index]
未来在这里以超链接的形式补充 异常处理 的内容
3.修改下标值为index的位置的元素
与第2点类似,一定要index合法才能修改,否则就抛出异常
def __setitem__(self, index, value):
if index < 0 or index >= self.index:
raise IndexError('index非法')
else:
self.data[index] = value
注意!!!
在getitem和setitem方法中,index == self.index都会抛出异常
因为表的下标是从0 到 n-1,没有n下标
4.判断顺序表是否为空
若顺序表为空,self.index 为 0 ,所以只需要判断其是否为0就好了
def empty(self):
if self.index == 0:
return True
else:
return False
当然也有更加优化的写法
return self.index == 0
另外要谨慎使用 is 这种写法,虽然它与 == 所表达的意思是一样的,用来判断是否相等
例如,在 Python 中,整数和字符串等简单对象的值是不可变的,所以对于相同的值,它们通常会被存储在相同的内存地址中,因此 is 运算符在这种情况下可以正确地比较两个对象是否相同。但是,对于一些可变对象,例如列表、字典等,即使它们包含相同的元素或键值对,它们也可能被存储在不同的内存地址中,因此使用 is 运算符比较它们时可能会得到错误的结果。
因此,建议在比较对象时,尽可能使用 == 运算符,只有在需要比较对象是否指向同一内存地址时,才使用 is 运算符。
python return self.index is 0
5.插入表头元素
如果顺序表以及达到最大容量,则退出,否则就在尾部插入元素
def append(self, value):
if self.index == self.max:
return
else:
self.data[self.index] = value
self.index += 1
6.在顺序表中任意位置插入元素 O(n)
def insert(self, index, value):
if index < 0 or index > self.index:
raise IndexError('index非法')
if index == self.max:
self.append(value)
# 直接raise IndexError('index非法')更好
else:
#self.data += [value]
# 调用方法也可以self.append(value)
for i in range(self.index, index, -1):
self.data[i] = self.data[i - 1]
self.data[index] = value
self.index += 1
以下为优化版本,在代码上省略了一个if语句,但是上述代码更容易理解
如果是在最后一个位置插入的话,就不需要交换位置了
def insert(self,index,value):
if index < 0 or index > self.index:
raise IndexError('index非法')
else:
#self.append(value)
for i in range(self.index,index,-1):
self.data[i] = self.data[i - 1]
self.data[index] = value
self.index += 1
self.append(value) 书上是由这段代码的,但是我建议不要加,通过遍历的方法打印出来,数组最后会多一个元素,并且去掉不影响 insert 方法
self.data += [value]
7.删除表尾元素
相当于这个表的长度直接减少了一个
def pop(self):
if self.empty():
return
self.index -= 1
8.删除任意位置的元素
用for循环将index后面的所有元素都向前移动一个位置
def delete(self,index):
if self.empty() or index >= self.index:
raise IndexError('Index非法')
for i in range(index,self.index):
self.data[i] = self.data[i + 1]
self.index -= 1
9.获取顺序表的长度
顺序表的长度记录在 self.index 中,直接返回即可
def length(self):
return self.index
10.遍历顺序表
一个一个打印出来即可
def traversal(self):
for i in range(self.index):
print(self.data[i],end = " ")
print()
单链表
1.节点定义代码
值域用来存放节点的值,指针域用来存放节点的直接后继指针
class Node(object):
def __init__(self,val):
self.val = val#数据域
self.next = None#后继节点的指针
2.初始化
声明头尾指针均指向空
class SingleLinkedList(object):
def __init__(self):
self.head = None
self.tail = None
头节点是链表的入口,尾节点是链表的出口
3.判断是否为空
若表头指针指向空,则单链表为空
def empty(self):
return self.head is None
4.获取单链表长度
只能通过遍历整个单链表,若当前节点不为空,则单链表的长度加 1
def length(self):
size = 0
#声明cur指针,用来遍历单链表
cur = self.head
while cur != None:
size += 1
cur = cur.next
return size
5.头插入法
~~~~~~~
因为是在头插入的,所以首先判断链表是否为空
若为空则需要将self.head和self.tail都指向新节点
否则只需要将新节点的next指向原来的头节点,再将self.head指向新节点即可
因为在链表头插入节点时,新节点将成为新的头节点,而尾节点不需要改变,因此self.tail指向原来的头节点即可。
def prepend(self,val):
newNode = Node(val)
if self.head is None:
self.head = newNode
self.tail = self.head
else:
newNode.next = self.head
self.head = newNode
6.在中间插入节点
def insert(self,index,value):
#定义一个cur用来遍历链表
cur = self.head
#一直遍历到下标为index - 1的节点
for i in range(index - 1):
cur = cur.next
#temp现在指向index - 1的元素,即index个节点
temp = cur.next
newNode = Node(value)
#将新节点的后继指针指向temp
newNode.next = temp
#将index个节点的直接后继指针指向新节点
cur.next = newNode
7.尾插入法
同样要判断链表是否为空
def append(self,val):
newNode = Node(val)
if self.empty():
self.head = newNode
self.tail = newNode
else:
#尾节点的后继指针指向新节点
self.tail.next = newNode
#尾指针指向新节点
self.tail = newNode
8.删除头节点
def del_first(self):
if self.empty():
raise IndexError('链表为空')
if self.length() == 1:
#将头尾指针指向空
self.head = None
self.tail = None
else:#链表长度大于 1
#将头指针指向第二个节点
self.head - self.head.next
9.删除尾节点
def del_lat(self):
if self.empty():
raise IndexError('链表为空')
if self.length() == 1:
self.head = None
self.tail = None
else:
pre = self.heal
cur = pre.next
while cur.next is not None:
pre = cur
cur = cur.next
cut = None
pre.next = None
self.tail = pre
10.删除任意位置的节点
def delete(self,index):
#删除下标值为index位置的节点,即删除第index+1个节点
if self.empty():
raise IndexError('链表为空')
if index < 0 or index >= self.length():
raise IndexError('Index非法')
if index == 0:
self.del_first()
elif index == self.length() - 1:
self.del_last()
else:
pre = self.head
#通过for循环使pre指针指向第index个节点
for i in range(index - 1):
pre = pre.next
#delNode为第index+1个节点
delNode = pre.next
#next为index+2个节点
next = delNode.next
#第index个节点的直接后继指向第index + 2个节点,即删除第index + 1个节点
pre.next = next
总结
下次再写