链表概念以及单向链表操作
1.链表
顺序表储存时会申请连续的储存空间,若要修改数据时,需要进行整体的数据搬迁,较为麻烦。而链表能够灵活运用计算机的内存空间,较为灵活。
链表的定义
链表是一种常见的数据结构,是一种线性表,储存时一个节点有两个域,一个域为信息域,另一个域为链接域,信息域储存数据信息,链接域储存下一个数据信息的地址。
2.单向链表
单向链表又称为单链表,是链表中最简单的一种形式,包含一个头节点,n个节点,且最后一个节点的链接域指向空值。
3.单向链表封装操作
class Node(object): def __init__(self,elem): self.elem = elem self.next = None class SingleLinkList(object): def __init__(self,node = None): self.__head = node def is_empty(self): return(self.__head == None) def length(self): # cur 游标 用来移动遍历节点 cur = self.__head # count 计数 count = 0 while cur != None: count += 1 cur = cur.next return count def travel(self): cur = self.__head while cur != None: print(cur.elem,end=' ') cur = cur.next def add(self,item): node = Node(item) node.next = self.__head self.__head = node def append(self,item): node = Node(item) if self.is_empty(): self.__head = node else: cur = self.__head while cur.next != None: cur = cur.next cur.next = node def insert(self,pos,item): ''' :param pos: 从0开始 :param item: :return: ''' if pos < 0: self.add(item) elif pos > (self.length()-1): self.append(item) else: pre = self.__head count = 0 while count < (pos-1): pre = pre.next count += 1 #循环退出后 pre指向pos-1的位置 else: node = Node(item) node.next = pre.next pre.next = node def remove(self,item): #pre和cur 两个游标差一个位置 pre = None cur = self.__head while cur != None: if cur.elem == item: #先判断当前节点是否为头节点 #如果是头节点 if cur == self.__head: self.__head = cur.next else: pre.next = cur.next break else: pre = cur cur = cur.next def search(self,item): cur = self.__head while cur != None: if cur.elem == item: return True else: cur = cur.next return False
=========================================================================
详解
节点的导入
class Node(object): def __init__(self,elem): self.elem = elem self.next = None
头节点定义 一般指向空
class SingleLinkList(object): def __init__(self,node = None): self.__head = node
判断是否为空的函数定义
def is_empty(self): return(self.__head == None)#直接判断头节点是否指向空即可
判断链表长度的函数定义
def length(self): # cur 游标 用来移动遍历节点 从0开始 cur = self.__head # count 计数 count = 0 while cur != None: #这个地方不是cur.next = None 不然会少计一个数 count += 1 cur = cur.next return count
遍历链表的函数定义
def travel(self): cur = self.__head #游标指向头节点 while cur != None:#当游标不为空时 一直向下遍历并打印 print(cur.elem,end=' ') cur = cur.next
头部添加元素的函数定义
def add(self,item): node = Node(item) #将新的元素定义成链表的数据结构 node.next = self.__head #将新节点的链接域指向头节点 self.__head = node #新的头节点定义为新的元素
尾部添加元素的函数定义
def append(self,item): node = Node(item) #将新的元素定义为链表结构 if self.is_empty(): #如果链表为空 头节点即时新的节点 self.__head = node else: cur = self.__head #当下一个链接域不指向为空 游标从0开始往下走 while cur.next != None: cur = cur.next cur.next = node #当游标走到最后一个元素时 元素的链接域指向新的节点
指定位置添加元素的函数定义
def insert(self,pos,item): ''' :param pos: 从0开始走 查找位置 ''' if pos < 0: #如果输入的位置小于零 判断为在头节点之前 插入元素 即为头部位置添加元素 self.add(item) elif pos > (self.length()-1):#如果输入位置为最后一个元素的位置 判断为在尾部位置添加元素 self.append(item) else: #找到指定位置的前一个位置 让pre的链接域指向新的节点 pre = self.__head count = 0 while count < (pos-1):#找到指定位置的前一个节点 pre = pre.next count += 1 #循环退出后 pre指向pos-1的位置 node = Node(item) #导入新的节点 node.next = pre.next #新节点的链接域指向前一个节点的链接域 pre.next = node
删除节点的函数定义
不是删除某个节点的操作 只是改变一个节点的链接域指向
def remove(self,item): #pre和cur 两个游标差一个位置 也可以只写pre游标 最后令pre.next = pre.next.next pre = None cur = self.__head while cur != None: if cur.elem == item: #先判断当前节点是否为头节点 #如果是头节点 if cur == self.__head: self.__head = cur.next else: pre.next = cur.next break else:# 遍历 pre = cur cur = cur.next
查找节点是否存在的函数定义
def search(self,item): cur = self.__head while cur != None: if cur.elem == item: return True else: cur = cur.next return False
4.链表和顺序表操作时间复杂度的对比
操作 | 链表 | 顺序表 |
---|---|---|
访问元素 | O(n) | O(1) |
在头部插入/删除 | O(1) | O(n) |
在尾部插入/删除 | O(n) | O(1) |
在中间插入/删除 | O(n) | O(n) |
访问元素 顺序表只需要访问对应的物理地址 而链表需要一个一个遍历
在头部数据操作上 链表只需要改变两个节点的链接域 而顺序表需要进行数据的搬迁
在尾部数据操作上 顺序表只需要找到对应的物质地址并添加元素 而链表需要遍历到最后一个cur.next = None时 再添加进新节点的链接域
在中间数据操作上 时间复杂度均为O(n) 但链表的O(n)是节点遍历造成的 而顺序表的O(n)是由于数据搬迁造成的