线性表

线性表是一种逻辑结构,包括顺序表(顺序表)、链表(单链表、双链表、循环链表、静态链表)两种存储结构

定义:具有相同数据类型的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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值