연결 리스트 (Linked Lists)

Henry Lee·2020년 12월 2일
0
post-thumbnail

본격적으로 낯설기 시작한다.. 이러나 저러나 핵심은 'link'

장점 : 쉽다. (빠르다.)
단점 : 메모리 소요 크다. i번째 v 찾는데 선형 배열보다 느리다.(빠르다며? ∵i가 없어서 처음부터 link 타고 탐색해야 한다.)

1. 일단, 구현

class Node:
	def __init__(self, item):
          self.data = item
          self.next = None
# a = Node(3)이면, self.data가 3인 Node가 생성(초기화)됨.


class LinkedList:
	def __init__(self):
          self.nodeCount == 0
          self.head == None
          self.tail == None
# L = LinkedList() 이면, 빈 연결 리스트가 생성(초기화)됨.

	def getAt(self, pos):
    		if pos<1 or pos>self.nodeCount:
            		return None
                    # LinkedList는 1 <= pos <= nodeCount니까, 이외 값은 안 받아.
           	i = 1
            	curr = self.head
            # head부터 탐색 시작
            	while i < pos:
            		curr = curr.next
                    	i += 1
                    # link 타고 다음 탐색, i로 pos를 계산(count).
                    return curr
                    
        def traverse(self):
        	result = []
            	curr = self.head
            # 마찬가지로 head부터 탐색 시작
                while curr:
                    answer.append(curr.data)
                    curr = curr.next
                # curr이 참이면 data를 result에 추가하고 link 타고 다음 탐색
                return result
                
        def insertAt(self, pos, newNode):
        	if pos<1 or pos>self.nodeCount+1:
            		return False
                    # 연결 리스트 끝에 추가하는 경우 nodeCount+1.
            	if pos == 1:
                	newNode.next = self.head
                    	self.head = newNode
                    # 연결 리스트 처음에 추가하는 경우 newNode의 link를 기존 head로 하고, head를 newNode로 변경.
                else:
                	if pos == self.nodeCount+1:
                    		prev = self.tail
                        # 연결 리스트 끝에 추가하는 경우 기존 tail을 prev에 두고.
                    	else:
                        	prev = self.getAt(pos-1)
                        # 끝에 추가하는 경우가 아닌 경우 getAt(pos-1)을 prev에 둔다. (∵prev의 link를 newNode로 변경해야함.)
                        newNode.next = prev.next
                        prev.next = newNode
                        
                        if pos == self.nodeCount+1:
                        	self.tail = newNode
                            # 끝에 추가하는 경우 tail을 newNode로 변경.
                        self.nodeCount += 1
                    # nodeCount 1 증가 (∵ 1개의 newNode 추가)
                        return True
                        
         def popAt(self, pos):
         	if pos<1 or pos>self.nodeCount:
            		raise IndexError
            	curr = self.getAt(pos)
                if pos == 1:
                	self.head = self.head.next
                else:
                	prev = self.getAt(pos-1)
                    	prev.next = curr.next
                    	if pos == self.nodeCount:
                        	self.tail = prev
                self.nodeCount -= 1
                if self.nodeCount == 0:
                	self.head = None
                    self.tail = None
                return curr.data
            

2. 왜 이렇게 복잡해졌냐? 연결 리스트 처음에 newNode를 넣거나 뺄때 문제가 되니까..
그래서 data가 None인 이른바 dummy node를 head에 넣고 구현!

class LinkedList:
	def __init__(self):
          self.nodeCount = 0
          self.head = Node(None)
          self.tail = None
          self.head.next = self.tail
    	# 이렇게 해서 head에 dummy node 삽입하고 그 link를 tail로 초기화. 단, dummy node는 node로 count 하지 않는다.
        
    	def traverse(self):
            result = []
            curr = self.head
            while curr.next:
              curr = curr.next
              result.append(curr.data)
            return result
        
        def getAt(self, pos):
        	if pos<0 or pos>self.codeCount:
            		return None
            	i = 0
            	curr = self.head
                while i<pos:
                    curr = curr.next
                    i += 1
                return curr
        # 아직은 쉬워졌나 모르겠지만..
        
        def insertAfter(self, prev, newNode):
            newNode.next = prev.next
            if prev.next = is None:
              self.tail = newNode
            prev.next = newNode
            self.nodeCount += 1
            return True
            
        def insertAt(self, pos, newNode):
            if pos<1 or pos>self.nodeCount+1:
            	return False
            if pos != 1 and pos==self.nodeCount+1:
            	prev = self.tail
            else:
            	prev = self.getAt(pos-1)
            return self.insertAfter(prev, newNode)
        # 삽입 코드가 쉬워짐. (∵ pos가 1이어도 신경 노노)
        
        def popAfter(self, prev):
            curr = prev.next
            if curr.data == None:
            	return None
            elif curr.next == None:
            	self.tail = prev
            prev.next = curr.next
            self.nodeCount -= 1
            return curr.data
            
        def popAt(self, pos):
            if pos<1 or pos>self.nodeCount:
            	raise IndexError
            prev = self.getAt(pos-1)
            return self.popAfter(prev)
        # 삭제 코드 쉬워짐. (이상한 에러 걱정 노노)

한줄평

중요한 메인 (여기서는 연결리스트가 link로 작동한다는 점)에 집중할 수 있도록, 특별한 케이스들의 피할 수 있는 코드 필요해 보인다. (연결리스트 처음에 node를 넣거나 뺄 때 이슈를 회피).

profile
Today I Learned. AI Engineer.

0개의 댓글