zoukankan      html  css  js  c++  java
  • 数据结构与算法7

    链表:(链表应用:操作系统的缓存、Dictionary)

      1. 链表由一系列数据记录构成,在每个记录里有个区域包含一个指向下一个数据记录的索引

      2. 链表vs数组列表

        (1)使用固定步数的操作可以在列表中任意节点做插入、删除操作

        (2)不允许随机访问

      3. 循环链表和双向链表

        

       4. 哨兵节点

        在某些实现中,可能会在第一个数据记录之前或者最后一个数据记录之后添加一个额外的哨兵节点或者哑元节点

        简化和加快一些列表处理的算法

        链表vs.动态数组
          — 都需要动态分配内存块
        — 动态数组:
          — 通过索引访问和分配非常快速,时间复杂度为O(1)
          — 添加元素(插入到数组的末尾)相对比较快,平摊时间复杂度为O(1)
          — 在动态数组里的任意位置添加和删除节点会很慢,时间复杂度为O(n)
          — 当需要对插入和删除做调整时,可能会出现不可预知的表现。
          — 会有一些未使用的空间
        — 链表:
          — 在列表中的任意位置做插入和删除都很快,时间复杂度为O(1)
          — 索引访问(随机访问)慢,时间复杂度为O(n)

      5. 抽象数据类型(ADT)列表操作

        (1)创建一个空列表

        (2)判断列表是否为空

        (3)确定列表中元素个数

        (4)在列表中给定位置添加一个元素

        (5)在列表中给定位置删除一个元素

        (6)删除列表中所有元素

        (7)在列表中取到给定位置上的元素

        (8)每一项操作的时间复杂度

    class Node:
        def __init__(self, value = None, next = None):
            self.value = value
            self.next = next
    class LinkedList:
        def __init__(self):
            self.head = Node(None, None)
            self.size = 0
    
        def get_first(self):
            if not self.head.next:
                print('LinkedList is empty')
            return self.head.next
        def get_last(self):
            if not self.head.next:
                print('LinkedList is empty')
            node = self.head
            while node.next != None:
                node = node.next
            return node
    
        def get(self, index):
            if (index < 0 or index >= self.length):
                print('index is out of bound');
            if not self.head.next:
                print('LinkedList is empty')
            node = self.head.next
            for i in range(index):
                node = node.next
            return node
        def add_first(self, value):
            node = Node(value, None)
            node.next = self.head.next
            self.head.next = node
            self.size += 1
        def add_last(self, value):
            new_node = Node(value,None)
            node = self.head
            while node.next != None:
                node = node.next
            node.next = new_node
            self.size += 1
        def remove_first(self):
            if not self.head.next:
                print("the linked list is empty")
            value = self.head.next
            self.head.next = self.head.next.next
            self.size -= 1
            return value
        def remove_last(self):
            if not self.head.next:
                print("the linked list is empty")
            node = self.head.next
            pre = self.head
            while node.next != None:
                pre = node
                node = node.next
            pre.next = None
            self.size -= 1
            return node.value
        def add(self, index, value):
            if (index < 0 or index > self.size):
                print('index is out of bound')
            if not self.head.next:
                print('LinkedList is empty')
            new_node = Node(value)
            node = self.head
            for i in range(index):
                node = node.next
            new_node.next = node.next;
            node.next = new_node;
            self.size += 1
        def remove(self, index):
            if (index < 0 or index >= self.size):
                print('index is out of bound');
            if not self.head.next:
                print("the linked list is empty")
            node = self.head
            for i in range(index):
                node = node.next
            result = node.next
            node.next = node.next.next
            self.size -= 1
            return result
        def print_list(self):
            node = self.head
            while node.next != None:
                node = node.next
                print(node.value, end = " ")
            print()
        def length(self):
            return self.size
    
    ll = LinkedList()
    ll.add_first(5)
    ll.add(1,8)
    ll.add_last(14)
    print(ll.length())
    ll.print_list()

      6. 练习1:删除链表中的节点,除了结尾,只允许访问那个节点

    def delete_node(node):
        print(node.value)
        node.value = node.next.value
        node.next = node.next.next

      7. 练习2:找到中间节点

    def find_middle(lst):
        assert lst.head is not None and lst.head.next is not None
        
        head = lst.head
        fast = head
        slow = head
        
        while fast is not None and fast.next is not None:
            fast = fast.next.next
            slow = slow.next
        
        return slow.value

      8. 练习3:是否有环

    def has_cycle(lst):
        return has_cycle_helper(lst.head)
    
    def has_cycle_helper(head):
        if head is None:
            return False
        
        slow = head 
        fast = head
        
        while fast is not None and fast.next is not None:
            fast = fast.next.next
            slow = slow.next
            
            if slow==fast:
                return True
            
        return False

      9. 练习4:找到环的开始:先跑两遍,一个快的是两倍速一个慢是一倍速,两者相遇后,将快的重归于原点,慢的继续跑,两个再同样速度跑,相遇就是环的起点

    def find_beginning(head):
        if head is None:
            return None
        
        slow = head
        fast = head
        
        while fast is not None and fast.next is not None:
            fast = fast.next.next
            slow = slow.next
            
            if slow==fast:
                fast = head
                break
            
        if fast is None or fast.next is None:
            return None
        
        while fast != slow:
            fast = fast.next
            slow = slow.next
    
        return slow

      9. 练习5:删除倒数第N个节点(限制:不能用size)

    def remove_nth(lst, n):
        assert n<=lst.length and n > 0
        
        fast = lst.head
        while n>0:
            fast = fast.next
            n = n - 1
            
        slow = lst.head
        while fast.next is not None:
            fast = fast.next
            slow = slow.next
            
        result = slow.next
        slow.next = slow.next.next
        
        lst.length = lst.length - 1
            
        return result

      10. 练习6:分半:给定一个列表,把它分成两个列表,一个是前半部分,一个是后半部分

    def split(head):
        if (head is None):
            return
        slow = head
        fast = head
        front_last_node = slow
        while (fast is not None):
            front_last_node = slow
            slow = slow.next
            fast = fast.next.next if fast.next is not None else None
        front_last_node.next = None
        front = head
        back = slow
        return (front, back)

       11. 练习7:合并两个排序链表

      Input: 1->2->4, 1->3->4

      Output: 1->1->2->3->4->4

    def mergeTwoLists1(l1, l2):
        dummy = cur = Node(0)
        while l1 and l2:
            if l1.value < l2.value:
                cur.next = l1
                l1 = l1.next
            else:
                cur.next = l2
                l2 = l2.next
            cur = cur.next
        cur.next = l1 or l2
        return dummy.next
    def mergeTwoLists2(l1, l2):
        if not l1 or not l2:
            return l1 or l2
        if l1.value < l2.value:
            l1.next = mergeTwoLists2(l1.next, l2)
            return l1
        else:
            l2.next = mergeTwoLists2(l1, l2.next)
            return l2

      练习8:

       找到两个相同链表的起始位置

        A: a1 → a2

                       ↘
    
                           c1 → c2 → c3
    
                       ↗    

        B: b1 → b2 → b3

      . 题解:先让AB同时跑,A先到终点,然后让A从B开始的位置再跑,B到终点后从A开始的位置继续跑,两者到达C1相遇

    def getIntersectionNode2(headA, headB):
        if headA and headB:
            A, B = headA, headB
            while A!=B:
                A = A.next if A else headB
                B = B.next if B else headA
            return A

      练习9:排序一个链表O(nlgn)

      先找到中点,然后将一个链表拆分为两个链表,然后将每一个链表排序合并

    def sortList(head):
        if head is None or head.next is None:
            return head
        mid = getMiddle(head)
        rHead = mid.next
        mid.next = None
        return merge(sortList(head), sortList(rHead))
    
    def merge(lHead, rHead):
        dummyNode = dummyHead = Node(0)
        while lHead and rHead:
            if lHead.value < rHead.value:
                dummyHead.next = lHead
                lHead = lHead.next
            else:
                dummyHead.next = rHead
                rHead = rHead.next
            dummyHead = dummyHead.next
        if lHead:
            dummyHead.next = lHead
        elif rHead:
            dummyHead.next = rHead
        return dummyNode.next
    
    def getMiddle(head):
        if head is None:
            return head
        slow = head
        fast = head
        while fast.next and fast.next.next:
            slow = slow.next
            fast = fast.next.next
        return slow

      练习10:Partition 链表

      给一个变量x, 链表左边所有的元素都比x小,x值右边所有元素值都比x大

    def partition(head, x):
        left_head = Node(None)  # head of the list with nodes values < x
        right_head = Node(None)  # head of the list with nodes values >= x
        left = left_head  # attach here nodes with values < x
        right = right_head  # attach here nodes with values >= x
        # traverse the list and attach current node to left or right nodes
        while head:
            if head.value < x:
                left.next = head
                left = left.next
            else:  # head.val >= x
                right.next = head
                right = right.next
            head = head.next
        right.next = None  # set tail of the right list to None
        left.next = right_head.next  # attach left list to the right
        return left_head.next  # head of a new partitioned list

       练习11:反转一个链表

    def reverse(lst):
        head = lst.head
        result = None
        current = head.next
        nxt = None
        
        while current is not None:
            nxt = current.next
            current.next = result
            result = current
            current = nxt
            
        head.next = result
    def reverseRecursion(node):
        if (node is None or node.next is None):
            return node
        p = reverseRecursion(node.next)
        node.next.next = node
        node.next = None
        return p
  • 相关阅读:
    洛谷1113 杂务
    MySQL中的各种引擎
    剑指offer第3题:从尾到头打印链表
    向一个GitHub repository添加协作者
    String、StringBuffer与StringBuilder之间区别
    java与C语言在字符串结束符上的区别
    git 查看远程分支、本地分支、创建分支、把分支推到远程repository、删除本地分支
    Git问题Everything up-to-date解决
    Mybatis 数据库物理分页插件 PageHelper
    时间序列分析发展史
  • 原文地址:https://www.cnblogs.com/lvxiaoning/p/11646808.html
Copyright © 2011-2022 走看看