线性表是一种逻辑结构,包括顺序表(顺序表)、链表(单链表、双链表、循环链表、静态链表)两种存储结构
定义:具有相同数据类型的n个数据元素的有限列表,处了第一个元素,每个元素有且仅有一个前驱,除了最后一个元素,每个元素有且仅有一个后继。
顺序表:表中逻辑顺序与物理顺序相同,随机访问,可以在0(1)找到指定元素,但是插入忽然删除需要移动大量元素。
顺序表:
class sqlist(object):
def __init__(self,length):
self.length=length
self.data=[]*self.length
self.num=0
def empty(self):
return self.num is 0
def full(self):
return self.num is self.length
继承了object对象,拥有了好多可操作对象,这些都是类中的高级特性,不继承object的话只有很少的可操作对象,实际上在python 3 中已经默认就帮你加载了object了(即便你没有写上object)。
python中__init__()函数即表示构造函数,通常在Python中创建类中见到。_init__
方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__
方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。
单链表:线性表的链式存储结构
class Node(object):
//定义类描述指针
def __init__(self,val,p=0):
self.data=val
self.next=p
class linklist(object):
//定义类描述单链表
def __init__(self):
self.head=None
def initlinklist(self,data):
//初始化单链表
self.head=Node(data[0])
p=self.head
for i in data[1:]:
p.next=Node(i)
p=p.next
def print(self):
p=self.head
while not p:
print(p.data)
p=p.next
单链表的头插法是逆序。
只有指向后继的指针,访问前驱结点指针是0(1),访问后继是0(1)。所以删除一个结点p,的时候,如果从头开始查找,0(n),但是把p复制给后继,删除后继0(1)。
循环单链表:把单链表最后一个指针不是NULL,改了指向头结点,形成一个环。任何位置操作一样,无需判断表头表尾。在对表头表尾操作的时候,可以只设尾结点r,这样头结点r.next ,在头结点和尾结点都是0(1)。
双链表:在单链表的节点中加入了前驱指针。插入删除0(1)
class Node(object):
def __init__(self,val,p=0):
self.data=val
self.prev=p
self.next=p
class Dlinklist(object):
def __init__(self):
self.head=0
def initlist(self,data):
self.head = Node(data[0])
p = self.head
for i in data[1:]:
node = Node(i)
p.next = node
node.prev = p
p = p.next
循环双链表,头结点的prev指向尾结点
静态链表:借助数组。
线性表的面试题
1.输入一个链表,输出该链表中倒数第k个结点。
定义两个指针
第一个指针从头结点开始遍历,向前走k-1步,第二个指针不动。
第二个指针从第k步,也开始从头指针开始遍历。
当第一个走到表尾,第2个刚好在倒数第k个
-*- coding:utf-8 -*-
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def FindKthToTail(self, head, k):
# write code here
if head==None or k==0:
return None
p1=head
p2=None
for i in range(1,k):
if p1.next!=None:
p1=p1.next
else:
return None
p2=head
while p1.next!=None:
p2=p2.next
p1=p1.next
return p2
2.输入一个链表,反转链表后,输出新链表的表头。
需要调整表中指针方向,加入调整i结点,需要知道它的前一个结点h,i.next=h,还需要知道i后一个结点p,因为前一个指针调整方向之后,后一个会丢失,我们要把后一个存下来。
头结点是原表的尾结点,当p.next=NULL时,说明是头结点
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回ListNode
def ReverseList(self, pHead):
# write code here
pNode=pHead
prev=None
pReverseHead=None
while pNode!=None:
pnext=pNode.next
if pnext==None:
pReverseHead=pNode
pNode.next=prev
prev=pNode
pNode=pnext
return pReverseHead
3.输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
定义三个指针,p1,p2分别从两个链表的头指针开始遍历,p为新表的指针
第一个头结点小于第2个,则第1个是合并后的头结点,然后p1=p1.next,接着与p2比较
如果p2.val大于p1.val则 p2=p2.next继续比较
-*- coding:utf-8 -*-
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
if pHead1==None:
return pHead2
if pHead2==None:
return pHead1
pmergehead=None
if pHead1.val<=pHead2.val:
pmergehead=pHead1
pmergehead.next=self.Merge(pHead1.next,pHead2)
else:
if pHead2.val<pHead1.val:
pmergehead=pHead2
pmergehead.next=self.Merge(pHead1,pHead2.next)
return pmergehead
4.输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
把原先指向左子结点的指针指向前一个,指向右子结点的指向后一个结点。
中序遍历是从小到大排序的,递归实现中序排序,得到有序序列,在给序列加指针。
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def Convert(self, pRootOfTree):
# write code here
if not pRootOfTree:
return None
self.atrr=[]
self.inorder(pRootOfTree)
for index,v in enumerate(self.atrr[:len(self.atrr)-1]):#加链
self.atrr[index].right=self.atrr[index+1]
self.atrr[index+1].left=v
return self.atrr[0]
def inorder(self,root):#中序遍历
if not root:
return
self.inorder(root.left)
self.atrr.append(root)
self.inorder(root.right)
5.
从尾到头打印链表
输入一个链表,从尾到头打印链表每个节点的值。
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
# write code here
if not listNode:
return []
res=[]
while listNode.next is not None:
res.append(listNode.val)
listNode=listNode.next
res.append(listNode.val)
return res[::-1]
6.在O(1)时间内删除链表节点。给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点。
我们要删除节点i,先把i的下一个节点j的内容复制到i,然后把i的指针指向节点j的下一个节点。此时再删除节点j,其效果等同于把节点i删除了。
class ListNode:
def __init__(self):
self.value = None
self.next_node = None
class Solution:
def delete_node(self,head_node,del_node):
"""
删除指定节点
"""
if not (head_node and del_node):
return False
#要删除的节点不是尾节点
if del_node.next_node:
del_next_node=del_node.next_node
del_node.value=del_next_node.value
del_node.next_node=del_next_node.next_node
del_next_node.value=None
del_next_node.next_node=None
#链表只要一个节点,删除头节点(也是尾节点)
elif del_node==head_node:
head_node=None
del_node = None
#链表中有多个节点,删除尾节点
else:
node=head_node
while node.next_node!=del_node:
node=node.next_node
node.next_node=None
del_node=None
return head_node
7.题目:删除链表中重复的节点。
题:在一个排序的链表中,请删除重复的节点,如1-2-3-3-4-4-5在重复的节点被删除后为1-2-5。
解题思路一:将链表元素保存在列表中,然后过滤掉出现次数大于1的值,只保留出现次数为1的值,再将新的列表建成链表的形式。
解题思路二:运用链表的操作,确保将重复的节点略过,始终连接不重复的值。
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplication(self, pHead):
# write code here
res=[]
while pHead:
res.append(pHead.val)
pHead=pHead.next
res=list(filter(lambda c:res.count(c)==1,res))
newList=ListNode(0)
pre=newList
for i in res:
node=ListNode(i)
pre.next=node
pre=pre.next
return newList.next
8.
题目:如果一个链表中包含环,如何找出环的入口节点?
解题分析:其实此题可以分解为三个题目:1)如何判断一个链表中是否包含环?2)如何找到环的入口节点?3)如何得到环中节点的数目?
解决此题:可以设置两个指针,一快一慢。
1.两个指针一个fast、一个slow同时从一个链表的头部出发
fast一次走2步,slow一次走一步,如果该链表有环,两个指针必然在环内相遇,(如果相遇就证明此链表包含环,否则没有环,解决问题1)
2.1 此时只需要把其中的一个指针重新指向链表头部,另一个不变(还在环内),
这次两个指针一次走一步,相遇的地方就是入口节点(解决问题2,得到环的入口节点)。
2. 2 接着步骤1,如果两个指针相遇,必然在环内,所以可以从这个节点出发,一遍继续向前移动,一遍计数,当再次回到这个节点时,就可以得到环中节点数了(解决问题3,得到环中节点数目)
# -*- coding:utf-8 -*-
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def EntryNodeOfLoop(self, pHead):
pFast=pHead
pSlow=pHead
while pFast!=None and pFast.next!=None:
pFast=pFast.next.next
pSlow=pSlow.next
#两个指针相遇且非空,则说明有环
if pFast==pSlow:
break
if pFast==None or pFast.next==None:
return None
pFast=pHead
while (pFast != pSlow):
pFast = pFast.next
pSlow = pSlow.next
#返回环的入口节点
return pFast