[python] 파이썬 연결리스트

파이썬에서 링크 된 목록을 사용하는 가장 쉬운 방법은 무엇입니까? 구성표에서 링크 된 목록은로 간단히 정의됩니다 '(1 2 3 4 5). 파이썬의리스트 [1, 2, 3, 4, 5]와 튜플 (1, 2, 3, 4, 5)은 실제로는 링크 된리스트가 아니며, 링크 된리스트는 상수 시간 연결과 같은 훌륭한 속성을 가지고 있지 않으며 별도의 부분을 참조 할 수 있습니다. 그것들을 불변으로 만들고 작업하기가 정말 쉽습니다!



답변

다음은 Martin v. Löwis의 표현을 기반으로 한 일부 목록 함수입니다 .

cons   = lambda el, lst: (el, lst)
mklist = lambda *args: reduce(lambda lst, el: cons(el, lst), reversed(args), None)
car = lambda lst: lst[0] if lst else lst
cdr = lambda lst: lst[1] if lst else lst
nth = lambda n, lst: nth(n-1, cdr(lst)) if n > 0 else car(lst)
length  = lambda lst, count=0: length(cdr(lst), count+1) if lst else count
begin   = lambda *args: args[-1]
display = lambda lst: begin(w("%s " % car(lst)), display(cdr(lst))) if lst else w("nil\n")

어디 w = sys.stdout.write

이중 연결 목록은 Raymond Hettinger의 정렬 된 세트 레시피 에서 널리 사용되지만 , 단일 연결 목록은 Python에서 실질적인 가치가 없습니다.

교육을 제외한 모든 문제에 대해 Python에서 단일 링크 목록을 사용한 적이 없습니다 .

Thomas Watnedal 훌륭한 교육 자료를 제안 했습니다 . 컴퓨터 과학자처럼 생각하는 방법, 17 장 : 연결 목록 :

연결된 목록은 다음 중 하나입니다.

  • 없음으로 표시되는 빈 목록 또는
  • 화물 객체 및 링크 된 목록에 대한 참조를 포함하는 노드.

    class Node:
      def __init__(self, cargo=None, next=None):
        self.car = cargo
        self.cdr = next
      def __str__(self):
        return str(self.car)
    
    def display(lst):
      if lst:
        w("%s " % lst)
        display(lst.cdr)
      else:
        w("nil\n")

답변

일부 필요에 따라 deque 도 유용 할 수 있습니다. O (1) 비용으로 deque의 양쪽 끝에 항목을 추가하고 제거 할 수 있습니다.

from collections import deque
d = deque([1,2,3,4])

print d
for x in d:
    print x
print d.pop(), d


답변

나는 다른 날에 이것을 썼다

#! /usr/bin/env python

class Node(object):
    def __init__(self):
        self.data = None # contains the data
        self.next = None # contains the reference to the next node


class LinkedList:
    def __init__(self):
        self.cur_node = None

    def add_node(self, data):
        new_node = Node() # create a new node
        new_node.data = data
        new_node.next = self.cur_node # link the new node to the 'previous' node.
        self.cur_node = new_node #  set the current node to the new one.

    def list_print(self):
        node = self.cur_node # cant point to ll!
        while node:
            print node.data
            node = node.next



ll = LinkedList()
ll.add_node(1)
ll.add_node(2)
ll.add_node(3)

ll.list_print()


답변

허용되는 답변은 다소 복잡합니다. 보다 표준적인 디자인은 다음과 같습니다.

L = LinkedList()
L.insert(1)
L.insert(1)
L.insert(2)
L.insert(4)
print L
L.clear()
print L

Thomas Watnedal이 권장 LinkedList하는 간단한 C ++ 디자인 및 17 장 : 링크 된 목록을 기반으로 하는 간단한 클래스 입니다.

class Node:
    def __init__(self, value = None, next = None):
        self.value = value
        self.next = next

    def __str__(self):
        return 'Node ['+str(self.value)+']'

class LinkedList:
    def __init__(self):
        self.first = None
        self.last = None

    def insert(self, x):
        if self.first == None:
            self.first = Node(x, None)
            self.last = self.first
        elif self.last == self.first:
            self.last = Node(x, None)
            self.first.next = self.last
        else:
            current = Node(x, None)
            self.last.next = current
            self.last = current

    def __str__(self):
        if self.first != None:
            current = self.first
            out = 'LinkedList [\n' +str(current.value) +'\n'
            while current.next != None:
                current = current.next
                out += str(current.value) + '\n'
            return out + ']'
        return 'LinkedList []'

    def clear(self):
        self.__init__()


답변

변경 불가능한 목록은 2 개의 튜플을 통해 가장 잘 표현되며 없음은 NIL을 나타냅니다. 이러한 목록의 간단한 공식화를 위해이 함수를 사용할 수 있습니다.

def mklist(*args):
    result = None
    for element in reversed(args):
        result = (element, result)
    return result

이러한 목록으로 작업하려면 메소드를 도입하는 것보다 LISP 함수의 전체 컬렉션 (즉, 첫 번째, 두 번째, n 번째 등)을 제공하고 싶습니다.


답변

다음은 파이썬의 시퀀스 유형과 비슷한 인터페이스를 가진 약간 더 복잡한 버전의 링크 된 목록 클래스입니다 (예 : 인덱싱, 슬라이싱, 임의 시퀀스와의 연결 등 지원). O (1) 접두어를 가져야하며, 튜플과 상호 교환없이 사용할 수 있어야하며 데이터를 복사하지 않으면 데이터를 복사하지 않습니다.

파이썬 클래스는 분명히 조금 더 무겁기 때문에 lisp cons 셀만큼 공간이나 시간 효율적이지 않을 것입니다 ( “__slots__ = '_head','_tail' 메모리 사용을 줄이기 위해 “로 있습니다). 그러나 원하는 큰 O 성능 특성을 갖습니다.

사용 예 :

>>> l = LinkedList([1,2,3,4])
>>> l
LinkedList([1, 2, 3, 4])
>>> l.head, l.tail
(1, LinkedList([2, 3, 4]))

# Prepending is O(1) and can be done with:
LinkedList.cons(0, l)
LinkedList([0, 1, 2, 3, 4])
# Or prepending arbitrary sequences (Still no copy of l performed):
[-1,0] + l
LinkedList([-1, 0, 1, 2, 3, 4])

# Normal list indexing and slice operations can be performed.
# Again, no copy is made unless needed.
>>> l[1], l[-1], l[2:]
(2, 4, LinkedList([3, 4]))
>>> assert l[2:] is l.next.next

# For cases where the slice stops before the end, or uses a
# non-contiguous range, we do need to create a copy.  However
# this should be transparent to the user.
>>> LinkedList(range(100))[-10::2]
LinkedList([90, 92, 94, 96, 98])

이행:

import itertools

class LinkedList(object):
    """Immutable linked list class."""

    def __new__(cls, l=[]):
        if isinstance(l, LinkedList): return l # Immutable, so no copy needed.
        i = iter(l)
        try:
            head = i.next()
        except StopIteration:
            return cls.EmptyList   # Return empty list singleton.

        tail = LinkedList(i)

        obj = super(LinkedList, cls).__new__(cls)
        obj._head = head
        obj._tail = tail
        return obj

    @classmethod
    def cons(cls, head, tail):
        ll =  cls([head])
        if not isinstance(tail, cls):
            tail = cls(tail)
        ll._tail = tail
        return ll

    # head and tail are not modifiable
    @property
    def head(self): return self._head

    @property
    def tail(self): return self._tail

    def __nonzero__(self): return True

    def __len__(self):
        return sum(1 for _ in self)

    def __add__(self, other):
        other = LinkedList(other)

        if not self: return other   # () + l = l
        start=l = LinkedList(iter(self))  # Create copy, as we'll mutate

        while l:
            if not l._tail: # Last element?
                l._tail = other
                break
            l = l._tail
        return start

    def __radd__(self, other):
        return LinkedList(other) + self

    def __iter__(self):
        x=self
        while x:
            yield x.head
            x=x.tail

    def __getitem__(self, idx):
        """Get item at specified index"""
        if isinstance(idx, slice):
            # Special case: Avoid constructing a new list, or performing O(n) length 
            # calculation for slices like l[3:].  Since we're immutable, just return
            # the appropriate node. This becomes O(start) rather than O(n).
            # We can't do this for  more complicated slices however (eg [l:4]
            start = idx.start or 0
            if (start >= 0) and (idx.stop is None) and (idx.step is None or idx.step == 1):
                no_copy_needed=True
            else:
                length = len(self)  # Need to calc length.
                start, stop, step = idx.indices(length)
                no_copy_needed = (stop == length) and (step == 1)

            if no_copy_needed:
                l = self
                for i in range(start):
                    if not l: break # End of list.
                    l=l.tail
                return l
            else:
                # We need to construct a new list.
                if step < 1:  # Need to instantiate list to deal with -ve step
                    return LinkedList(list(self)[start:stop:step])
                else:
                    return LinkedList(itertools.islice(iter(self), start, stop, step))
        else:
            # Non-slice index.
            if idx < 0: idx = len(self)+idx
            if not self: raise IndexError("list index out of range")
            if idx == 0: return self.head
            return self.tail[idx-1]

    def __mul__(self, n):
        if n <= 0: return Nil
        l=self
        for i in range(n-1): l += self
        return l
    def __rmul__(self, n): return self * n

    # Ideally we should compute the has ourselves rather than construct
    # a temporary tuple as below.  I haven't impemented this here
    def __hash__(self): return hash(tuple(self))

    def __eq__(self, other): return self._cmp(other) == 0
    def __ne__(self, other): return not self == other
    def __lt__(self, other): return self._cmp(other) < 0
    def __gt__(self, other): return self._cmp(other) > 0
    def __le__(self, other): return self._cmp(other) <= 0
    def __ge__(self, other): return self._cmp(other) >= 0

    def _cmp(self, other):
        """Acts as cmp(): -1 for self<other, 0 for equal, 1 for greater"""
        if not isinstance(other, LinkedList):
            return cmp(LinkedList,type(other))  # Arbitrary ordering.

        A, B = iter(self), iter(other)
        for a,b in itertools.izip(A,B):
           if a<b: return -1
           elif a > b: return 1

        try:
            A.next()
            return 1  # a has more items.
        except StopIteration: pass

        try:
            B.next()
            return -1  # b has more items.
        except StopIteration: pass

        return 0  # Lists are equal

    def __repr__(self):
        return "LinkedList([%s])" % ', '.join(map(repr,self))

class EmptyList(LinkedList):
    """A singleton representing an empty list."""
    def __new__(cls):
        return object.__new__(cls)

    def __iter__(self): return iter([])
    def __nonzero__(self): return False

    @property
    def head(self): raise IndexError("End of list")

    @property
    def tail(self): raise IndexError("End of list")

# Create EmptyList singleton
LinkedList.EmptyList = EmptyList()
del EmptyList


답변

llist — Python의 링크 된 목록 데이터 유형

llist 모듈은 연결된 목록 데이터 구조를 구현합니다. 이중 연결 목록, 즉 dllist단일 연결 데이터 구조를 지원 sllist합니다.

dllist 객체

이 개체는 이중 연결 목록 데이터 구조를 나타냅니다.

first

dllistnode목록의 첫 번째 개체 None목록이 비어있는 경우

last

dllistnode목록의 마지막 개체 목록이 비어있는 경우 없음

dllist 객체는 다음 방법도 지원합니다.

append(x)

x목록의 오른쪽에 추가 하고 삽입 된 상태로 반환 dllistnode합니다.

appendleft(x)

x목록의 왼쪽에 추가 하고 insert를 반환 dllistnode합니다.

appendright(x)

x목록의 오른쪽에 추가 하고 삽입 된 상태로 반환 dllistnode합니다.

clear()

목록에서 모든 노드를 제거하십시오.

extend(iterable)

iterable목록의 오른쪽 에서 요소를 추가 하십시오.

extendleft(iterable)

iterable목록의 왼쪽 에서 요소를 추가 하십시오.

extendright(iterable)

iterable목록의 오른쪽 에서 요소를 추가 하십시오.

insert(x[, before])

지정되지 않은 x경우 목록의 오른쪽에 추가 before하거나 x의 왼쪽에 삽입 하십시오 dllistnode before. 삽입 삽입 dllistnode.

nodeat(index)

반환 노드 (유형의 dllistnode)에서 index.

pop()

목록의 오른쪽에서 요소 값을 제거하고 반환하십시오.

popleft()

목록의 왼쪽에서 요소 값을 제거하고 반환하십시오.

popright()

목록의 오른쪽에서 요소의 값을 제거하고 반환

remove(node)

없애다 node목록에서 하고 저장된 요소를 리턴하십시오.

dllistnode 사물

수업 llist.dllistnode([value])

다음과 같이 초기화 된 새 이중 연결 목록 노드를 반환합니다 (선택 사항). value .

dllistnode 객체는 다음과 같은 속성을 제공합니다.

next

목록의 다음 노드 이 속성은 읽기 전용입니다.

prev

목록의 이전 노드 이 속성은 읽기 전용입니다.

value

이 노드에 저장된 값.
이 참조에서 컴파일

슬릿

클래스 llist.sllist([iterable])
반환의 요소로 초기화 된 새로운 단일 연결리스트 iterable. iterable을 지정하지 않으면 새 항목 sllist이 비어 있습니다.

sllist개체에 대해 유사한 속성 및 작업 집합이 정의되어 있습니다. 자세한 내용은이 참조를 참조하십시오.