카테고리 없음

자료구조 6-2장 | Linked List | 숙명여대 학점교류

토마토. 2021. 12. 28. 14:22

학점교류로 듣는 숙명여대 자료구조

day 5. 2021.12.28. 화요일

 

 

 


to be continued..... :D

 

linked stack and queue

linked stack

* isEmpty : 스택이 비어있는가? 

linear list에서 top, front로 isEmpty를 체크하였다.

고정 크기가 아닌 경우, 함수 length와 같은 것을 활용할 수 있다. 

head == None인 경우에 empty인 것이다 ~

비어있을 때랑 비어있지 않을 때 코드가 달라져야 한다. 

* peek_front : 첫 원소를 본다(꺼내지 않음)

* add_front : push

* pop_front : pop

 

linked stack의 구조 LIFO

정적 배열과 달리.. (파이썬은 아니지만..) 문제는 size를 정하는 것

고정된 크기로 사용을 해주어야 한다. 

연결 리스트는 개수를 정해주지 않아도 된다는 장점이 있다. 

 

* isEmpty

def isEmpty(self):
    return not self.head

* peek_front

def peek_front(self):
    if isEmpty():
        print("List Empty")
    else:
        return self.head.data

* add_front

def add_front(self, item):
    node = Node(item)
    if not self.head:
        self.head = node
        self.tail = node
    else:
        node.link = self.head
        self.head = node

노드의 링크가 잘 안되었다. 

head가 참조한 링크를 노드가 참조한다. 

 

* pop_front

def pop_front(self):
    if not self.head:
        print("List Empty")
        return None
    else:
        temp= self.head
        self.head = self.head.link
        item = temp.data
        del temp
        return item

 

 

 

+ 과제 꿀팁 )

값은 당연하고, 코드 안에서 documentation을 해주어야 한다. 

함수, 변수의 의미를 주석을 달아주기!

case를 빠뜨리지 말아야 한다. 

 

 

Linked Queue

* isEmpty

* add_rear : add

* pop_front : del 

뒤에 붙인다 / 앞에서 꺼낸다

 

* add_rear

노드를 만들어서 붙인다. 

empty인 경우 / empty가 아니었던 경우로 나눈다.

def add_rear(self, item):
    node = Node(item)
    if not self.head:
        self.head = node
        self.tail = node
# tail이 none이면 error
# 발생하므로 이 부분 필요
    elif self.tail:
        self.tail.link = node
        self.tail = node

그리고 tail을 업데이트 해야한다. 

연결 리스트는 케이스가 커버되었는지 보아야한다. 

 

모든 일을 if-else로 생각한다. 

if / else if / else

세상일은 fuzzy한 경우가 많다 -> AI가 처리함

기초가 튼튼해야 함

 

-> stack / queue / deque 데크

deque

* double ended queue

stack과 큐의 중간적인 자료 구조

stack : 앞에서 add / del

que : 앞에서 del / 뒤에서 add

deque : 앞에서 add / del, 뒤에서 add / del 되도록 만든 것이다. 

 

따라서 함수가 총 네 개 필요하다.

* add_front -> 앞서 함

* add_rear -> //

* pop_front -> //

* pop_rear

 

head, tail 필요할 것임

딜레마가 존재하는데, 마지막 노드가 참조해왔지만, 직전 노드는 알지 못한다는 것이 문제다. 

SLL에서는 단방향으로 연결되어있다. tail이 사라지기 때문에..

head부터 탐색해서 해준다. 

(find가 해줌)

prev, temp를 같이 알려준다. 

여기서부터는 어렵다 ㅠㅠ

 

def pop_rear(self):
    if not self.head:
        print("List Empty")
        return None
    else:
        item = self.tail.data
        prev, temp = self.find(item)
        self.tail = prev
        if prev:
            prev.link = None
        else:
            self.head = None
        del temp
        return item

- 노드가 1개인 경우 : 한 개를 삭제하면 empty list가 된다. 

- 여러 개인 경우 : prev.link = None으로 업데이트 해준다. 

 

-> 예습을 해와야한다 ㅠㅠ

 

 

linked polynomial

a = 5x^12 - 6x^8 + 13x^3b = 10x^15 + 4x^8 + 9

 

계수, 변수, 지수가 있다. 계수와 지수를 튜플로 출력한다.

 

a = [(5,12),(-6,8),(13,3)]
b = [(10,15),(4,8),(9,0)]
d = [(10,15),(5,12),(-2,8),(13,3),(9,0)]

 

생각해보자!

 

def del_list(self):
    node = self.head
    while node:
        temp = node
        node = node.link
        del temp
    print("List is deleted")
    self.head = None

node는 움직이고, 

temp가 가리키는 node를 바꾸어가면서

temp를 제거한다

node가 참조하는 대상이 바뀐다면?

 

* concatenate list

def concat(self, second):
    if not self.head: # first list는 none
        return second
    elif second: # 두 리스트 모두 none 아님
        temp = self.head # first 리스트의 헤드
        while temp.link: # first list의 마지막 노드 찾기
            temp = temp.link 
        temp.link = second
    return self.head
# Time Complexity = O(n) (n= length of first)
# first.concat(second) 같은 형태

 

단, tail node가 있는 경우에는 tail.link로 second.head 이어주면 된다.

 

표로 그리면, case를 잘 찾는 것이 중요하다고 할 수 있다.

 

 

circular list

  • chain

: a linked list whose the last node has a None link

  • circular link

: a linked list whose last node is circularly connected with the first node

: easy to change the list pointer

: 전체 노드가 연결되어있어 시작 노드를 바꾸어도 계속해서 이어진다. 

: chain의 경우 그렇지 않음

 

  • length

complexity : O(length of list)

마지막 노드의 link가 head이다. 

def length_list(self):
    if not self.head: return 0
    count = 0
    temp = self.head
    while True:
        count += 1
        temp = temp.link
        if temp == self.head: break
    return count

코드가 어떻게 달라져야 하는가? (chain and circular) 결국 종료 조건(1바퀴를 다 돈)이 다르다. 

 

  • add_sort

add a node to circular list orderly

 

전 노드를 알고 있어야 한다. prev를 업데이트하면서 가야한다. 

shorter [pass] / equal [duplicate] / longer [insert]

 

def add_sort(self, item):
    node = Node(item)
    if not self.head:
        self.head = node
        self.tail = node
        node.link = self.head
        return
    temp = self.head
    prev = None
    while temp:
        if item > temp.data: # 큼
            prev = temp
            temp = temp.link
        elif item == temp.data: # 같음
            print("Duplicate item")
            return
        else: # 작음
            node.link = temp
            if prev:
                prev.link = node
            else:
                self.head = node
                self.tail.link = node
            return
        if temp == self.head: break
    
    # 최댓값 | 기존 노드보다 가장 큰 값이 들어온 경우
    node.link = self.head
    prev.link = node

 

 

 

reverse list

  • reverse a list

[a,b,c,d,e]를 [e,d,c,b,a]로 바꿔준다. 

case : empty list일 때

case : single node일 때

그대로 출력

case : 그보다 많을 때

reverse가 필요하다. 

  • time complexity

O(list length)

 

def reverse(self):
    first = self.head
    second = third = None
    self.tail = self.head
    while first:
        third = second
        second = first
        first = first.link
        second.link = third
    self.head = second
    return

퍼스트가 이동

역방향으로 링크가 재설정된다. 

두 번 끝나면? 

2 개의 node가 더 필요하다. 

first, second, third가first를 역방향으로 이동시키면서, second/third가 순차적으로 따라가도록 했다. 

 

 

doubly linked list