数据结构-链表
一.介绍
采用链式方式存储的线性表称为链表,链表用若干地址分散的存储单元存储数据,逻辑上相邻的数据元素在物理位置上不一定相邻
二.单链表
单链表是指节点中只包含一个指针域的链表,指针域中的存储着指向后继节点的指针。单链表的头指针是线性表的起始地址,是线性表中第一个数据元素的存储地址,可作为单链表的唯一标识。单链表的尾节点没有后继节点,所以其指针域值为None。
为了操作简单,在第一个节点之前增加头节点,单链表的头指针指向头节点,头节点的数据域不存放任何数据,指针域存放指向第一个节点的指针。空单链表的头指针head为None。
单链表的节点的存储空间是在输入和删除过程中动态申请和释放的,不需要预先分配,从而避免了顺序表因存储空间不足需要扩充空间和复制元素的过程,避免了顺序表因容量过大造成内存资源浪费的问题,提高了运行效率和存储空间的利用率
1.节点类描述
class Node(object): def __init__(self,data=None,next=None): self.data = data self.next = next
2.单链表类描述
class LinkList(IList): def __init__(self): self.head = Node() #构造函数初始化头节点 def cerate(self,l,order): if order: self.create_tail(l) else: self.create_head(l) def create_tail(self,l): pass def create_head(self,l): pass def clear(self): """ 将线性表置为空表""" self.head.data = None self.head.next = None def isEmpty(self): """判断线性表是否为空""" return self.head.next == None def length(self): """返回线性表的长度""" p = self.head.next length = 0 while p is not None: p = p.next length += 1 return length def get(self,i): """读取并返回线性表中的第i个元素""" pass def insert(self,i,x): """(带头节点)的插入x为第i个元素""" pass def remove(self,i): """删除第i个元素""" pass def indexOf(self,x): """返回元素x首次出现的位序号""" pass def display(self): """输出线性表中各个数据的元素的值""" p = self.head.next while p is not None: print(p.data,end=' ') p = p.next
3.单链表的基本操作的实现
3.1.查找操作
(1)位序查找get(i)返回线性表中第i 个节点设的数据域的值
def get(self,i): """读取并返回线性表中的第i个元素""" p = self.head.next #p指向单链表的首节点 j = 0 #从首节点开始向后查找,直到p指向第i个节点 while j < i and p is not None: p = p.next j += 1 if j > i or p is not None: raise Exception("第"+i+"个元素不存在") return p.data
(2)按值查找
def indexOf(self,x): """返回元素x首次出现的位序号""" p = self.head.next j = 0 while p is not None and not (p.data == x): p = p.next j += 1 if p is not None: return j else: return -1
3.2.插入操作
插入操作insert(i,x)是在长度为n的单链表的第i个节点之前插入数据域为x的新节点,其中0《 i 《 n ,当i=0时,在表头插入,当i=n时,在表尾插入
步骤:
(1)查找到插入位置的前驱节点,即第i-1个节点
(2)创建数据域值为x的新节点
(3)修改前驱节点的指针域为指向新节点的指针,新节点的指针域为指向原第i 个节点的指针
带头节点的插入:
def insert(self,i,x): """(带头节点)的插入x为第i个元素""" p = self.head j = -1 while p is not None and j < i-1: p = p.next j += 1 if j > i-1 or p is None: raise Exception("插入位置不合法") s = Node(x,p.next) p.next = s
不带头节点的插入:
def insert(self,i,x): """(不带头节点)的插入x为第i个元素""" p = self.head j = -1 while p is not None and j < i-1: p = p.next j += 1 if j > i-1 or p is not None: raise Exception("插入位置不合法") s = Node(data=x) if i == 0: s.next = self.head else: s.next = p.next p.next = s
3.3删除操作
步骤:
(1)判断单链表是否为空
(2)查找待删除节点的前驱节点
(3)修改前驱节点的指针域为待删除节点的指针域
def remove(self,i): """删除第i个元素""" p = self.head j = -1 #寻找第i个节点的前驱节点 while p is not None and j < i-1: p = p.next j += 1 if j > i-1 or p.next is None: raise Exception("删除位置不合法") p.next = p.next.next
四.实践
1.编写一组程序,实现某班学生姓名数据的建表、展示、查找、定位、插入、删除、求表长等操作
测试用例:
依次输入学生姓名:赵一 钱二 孙三 李四 周五 吴六 郑七 王八
(1)展示班级所有学生姓名和人数
(2)查找李四在表中的位置
(3)在王八后面加入新生郑九
(4)删除学生赵一
from abc import ABCMeta,abstractmethod,abstractproperty class IList(metaclass=ABCMeta): @abstractmethod def clear(self): """ 将线性表置为空表""" pass @abstractmethod def isEmpty(self): """判断线性表是否为空""" pass @abstractmethod def length(self): """返回线性表的长度""" pass @abstractmethod def get(self,i): """读取并返回线性表中第i个元素""" pass @abstractmethod def insert(self,i,x): """插入x作为第i个元素""" pass @abstractmethod def remove(self,i): """删除第i个元素""" pass @abstractmethod def indexOf(self,x): """返回元素x首次出现的位序号""" pass @abstractmethod def display(self): """输出线性表中各个数据元素的值""" pass class Node(object): def __init__(self,data=None,next=None): self.data = data self.next = next class LinkList(IList): def __init__(self): self.head = Node() #构造函数初始化头节点 def cerate(self,l,order): if order: self.create_tail(l) else: self.create_head(l) def create_tail(self,l): for item in l: self.insert(self.length(),item) def create_head(self,l): for item in l: self.insert(0,item) def clear(self): """ 将线性表置为空表""" self.head.data = None self.head.next = None def isEmpty(self): """判断线性表是否为空""" return self.head.next == None def length(self): """返回线性表的长度""" p = self.head.next length = 0 while p is not None: p = p.next length += 1 return length def get(self,i): """读取并返回线性表中的第i个元素""" p = self.head.next #p指向单链表的首节点 j = 0 #从首节点开始向后查找,直到p指向第i个节点 while j < i and p is not None: p = p.next j += 1 if j > i or p is not None: raise Exception("第"+i+"个元素不存在") return p.data def insert(self,i,x): """(带头节点)的插入x为第i个元素""" p = self.head j = -1 while p is not None and j < i-1: p = p.next j += 1 if j > i-1 or p is None: raise Exception("插入位置不合法") s = Node(x,p.next) p.next = s def insert(self,i,x): """(不带头节点)的插入x为第i个元素""" p = self.head j = -1 while p is not None and j < i-1: p = p.next j += 1 if j > i-1 or p is not None: raise Exception("插入位置不合法") s = Node(data=x) if i == 0: s.next = self.head else: s.next = p.next p.next = s def remove(self,i): """删除第i个元素""" p = self.head j = -1 #寻找第i个节点的前驱节点 while p is not None and j < i-1: p = p.next j += 1 if j > i-1 or p.next is None: raise Exception("删除位置不合法") p.next = p.next.next def indexOf(self,x): """返回元素x首次出现的位序号""" p = self.head.next j = 0 while p is not None and not (p.data == x): p = p.next j += 1 if p is not None: return j else: return -1 def display(self): """输出线性表中各个数据的元素的值""" p = self.head.next while p is not None: print(p.data,end=' ') p = p.next
L = LinkList() for i in range(8): s = input("请输入学生名称%i:"%(i+1)) L.insert(i,s) #依次输入:赵一、钱二、孙三、李四、周五、吴六、郑七、王八 print("(1)班级学生:",end=' ') L.display() print("班级人数:",L.length()) print("(2)李四在表中的位置:",L.indexOf('李四')) L.insert(L.indexOf('王八')+1,'郑九') print('(3)在王八的后面插入郑九后:',end=' ') L.display() print("班级人数:",L.length()) L.remove(L.indexOf('赵一')) print('(4)删除赵一后:',end=' ') L.display() print("班级人数:",L.length())
结果:
请输入学生名称1:赵一 请输入学生名称2:钱二 请输入学生名称3:孙三 请输入学生名称4:李四 请输入学生名称5:周五 请输入学生名称6:吴六 请输入学生名称7:郑七 请输入学生名称8:王八 (1)班级学生: 赵一 钱二 孙三 李四 周五 吴六 郑七 王八 班级人数: 8 (2)李四在表中的位置: 3 (3)在王八的后面插入郑九后: 赵一 钱二 孙三 李四 周五 吴六 郑七 王八 郑九 班级人数: 9 (4)删除赵一后: 钱二 孙三 李四 周五 吴六 郑七 王八 郑九 班级人数: 8
2.编写一组程序,实现一元多项式的加法运算
举例:
p1 = 3x^3 + 5x^2 + 4x
p2 = x^5 + 3x^2
p1+p2 = x^5 + 3x^3 + 8x^2 + 4x
输入:从大到小依次输入所要输入的两个一元多项式的系数和指数
输出:输出多元式p1,p2以及两式相加的结果
class PloyNode(object): def __init__(self,a,e): self.a = a #系数 self.e = e#指数 def add(p1,p2): L = LinkList() i = j = 0 #i指针指向p1,j指针指向p2 while i < p1.length() and j < p2.length(): x,y = p1.get(i),p2.get(j) #如果此时选择的两项指数相等 if x.e == y.e: #将系数相加插入 L.insert(L.length(),PloyNode(x.a+y.a,x.e)) i += 1 j += 1 elif x.e > y.e: L.insert(L.length(),PloyNode(x.a,x.e)) i += 1 else: L.insert(L.length(),PloyNode(y.a,y.e)) j += 1 #如果剩下的为p1,且p1的指数都比之前插入的小 while i < p1.length(): x = p1.get(i) #插入p1剩下的部分 L.insert(L.length(), x) i += 1 #如果剩下的为p2,且p2的指数都比之前插入的小 while j < p2.length(): y = p2.get(j) # 插入p2剩下的部分 L.insert(L.length(), y) j += 1 return L p1 = LinkList() p2 = LinkList() #多项式 3x^3 + 5x^2 + 4x p1.insert(0,PloyNode(3,3)) p1.insert(1,PloyNode(5,2)) p1.insert(2,PloyNode(4,1)) #多项式 p2 = x^5 + 3x^2 p2.insert(0,PloyNode(1,5)) p2.insert(1,PloyNode(3,2)) #相加 L = add(p1,p2) for i in range(L.length()-1): x = L.get(i) #输出每一项 print("%sx^%s + "%(x.a,x.e),end=' ') #最后一项没有+ x = L.get(L.length()-1) print("%sx^%s"%(x.a,x.e))
输出:
1x^5 + 3x^3 + 8x^2 + 4x^1