Data Structure & Algorithm

[자료구조] 원형 리스트, 이중 리스트 구현 (in python)

여뉴누 2023. 6. 18. 21:41
728x90
강의 출처) 숙명여자대학교 소프트웨어융합전공 강의 "자료구조", 이현자 교수님

원형 리스트

1. 원형 리스트란 ?

  • 단일 리스트에서의 마지막 노드가 맨처음 노드와 연결된 형태
  • 마지막 노드의 link가 NULL이 아님
  • head가 변경되어도 연결리스트를 유지할 수 있음

 

2. 원형 리스트 구현

1) 노드 기본 구현

class Node:
  def __init__(self, item):
    self.data = item
    self.link = None

2) 원형 연결 리스트 연산 종류

  • 삽입 연산
  • 삭제 연산
  • 리스트 길이 계산

3) 원형 연결 리스트 구현

(1) 삽입 연산

  • 삽입 연산의 경우의 수 세 가지
    • 빈리스트에 삽입하는 경우
    • 리스트 맨 앞 위치로 삽입하는 경우
    • 리스트 중간(OR 끝)에 삽입하는 경우

  • 코드 구현1 - 빈리스트에 삽입하는 경우 
    • 삽입되는 노드가 head이면서 tail
    • 원형 연결 리스트에서는 노드가 한 개일때 자기 자신을 연결
if self.head is None: 
    # head노드가 없다 = 빈리스트이다 -> 빈리스트이면
  self.head = node 
    # 삽입된 노드는 head노드이면서
  self.tail = node
    # tail 노드이기도 하다
  node.link = self.head
    # self.head를 node의 link가 연결하도록 해서 node가 
    자기 자신을 순환하는 원소가 한 개인 연결리스트가 될 수 있도록
  return
  • 코드 구현2 - 리스트 맨 앞 위치로 삽입하는 경우
    • 원래의 head를 삽입 노드의 link에 연결
    • 삽입 노드를 head로 지정
elif prev is None:
	# 앞 노드가 없다 = 리스트의 맨 앞에 노드를 삽입하면 된다
	node.link = self.head
		# 원래의 head 노드를 삽입 노드의 link에 연결한 뒤
	self.head = node
		# node를 head노드로 지정
	return
  • 코드 구현3 - 리스트 중간(OR 끝)에 삽입하는 경우
    • 삽입할 노드의 앞 노드를 찾고
    • 없으면 그대로 STOP / 있으면 KEEP GOING
    • node의 링크에 앞 링크를 저장
    • 앞노드의 링크에는 node를 저장
    • 만약 앞노드의 link가 head와 연결되어 있으면 = 앞노드가 tail 노드다 -> node가 tail 노드
pprev, prev = self.find(prev) 
	# prev값이 None이 아니었다면 prev값을 찾아보자
if prev is None: 
	# 찾아봤는데도 리스트 안에 prev값이 존재하지 않으면
		print("Not Exist previous node")
		return
else:
	# prev값이 실제로 리스트 안에 존재하면
	if prev.link == self.head: self.tail = node
		# prev의 link에 head가 연결되어 있다는건 prev가 tail 노드였다는 의미 -> node를 tail 노드로
	node.link = prev.link 
		# prev의 link를 node의 link에 연결한 뒤
	prev.link = node
		# node를 prev.link에 연결해줌

(2) 삭제 연산

  • 삭제 연산의 경우의 수
    • 삭제 노드가 head 노드
    • 삭제 노드가 tail 노드
    • 삭제 노드가 중간 어딘가의 노드
  • 코드 구현
  def c_delete(self, item):
    if self.head is None: 
        # head 노드 없다 = 빈리스트다
      print("Empty List")
      return
    prev, node = self.find(item)
      # 삭제할 node 찾고
    if node is None:
        # 삭제할 노드가 리스트 내부에 존재하지 않으면
      print("Non Exist node")
      return
    if prev:
        # prev가 존재하면
      prev.link = node.link
        # prev의 링크에 삭제할 노드가 연결하고 있던 노드를 연결시켜주고
      if self.tail == node : self.tail = prev
        # 그 노드가 tail이었으면 전 노드가 tail이 됨
      print("Delete complitely")
    else:
        # 삭제할 노드가 맨 앞의 값이다
      if self.head == node:
        # 노드가 head였으면
        self.head == node.link
          # node가 연결하고 있던 노드를 head 노드로 만들어주고
        print("Head delete")
      if self.tail == node:
        # node가 tail 이었으면 -> 한개의 노드만 있었다면
        self.tail = self.head
          # head, tail 연결 -> 빈리스트
    del node
      # 노드 삭제

(3) 리스트 길이 계산

  • 코드 구현
  def length_list(self):
    if not self.head : return 0
    count = 0
    temp = self.head
    while temp.link:
      count += 1
      temp = temp.link
      if temp == self.head : break
      	# 한바퀴 다 돌아서 head노드로 다시 돌아오면 break

+) 원형 리스트에서 원소 찾는 함수

... 내가 코드 짜서 틀린 부분 있을지도 몰루 ...

  def find(self, item):
    temp = self.head
    prev = None
    c = 0
    while temp:
      if temp.data == item:
        return prev, temp
      prev = temp
      temp = temp.link
      c += 1
      if temp == self.head:
        print(c)
        return None, None

4) 전체 코드

class Node:
  def __init__(self, item):
    self.data = item
    self.link = None

class Circularlist:
  def __init__(self):
    self.head = None
    self.tail = None
  
  def isEmpty(self):
    return not self.head
  
  def length_list(self):
    if not self.head : return 0
    count = 0
    temp = self.head
    while temp.link:
      count += 1
      temp = temp.link
      if temp == self.head : break
    return count
  
  def add_rear(self, item): # 노드를 끝에만 추가하는 함수
    node = Node(item)
    if self.head is None:
      self.head = node
      self.tail = node
    else:
      self.tail.link = node
      self.tail = node
    node.link = self.head
  
  def view(self):
    temp = self.head
    print('[', end = ' ')
    if self.head == self.tail:
      print(temp.data, end = ' ')
    else:
      while self.head != self.tail:
        print(temp.data, end = ' ')
        temp = temp.link
        if temp is self.head : break
    print(']', end = ' ')
    if self.head:
      print("H = ", self.head.data, "T =", self.tail.data)
    else:
      print("Empty list")

  def c_insert(self, prev, item): # 어디든 노드를 추가할 수 있는 함수
    node = Node(item)
    if self.head is None: 
      self.head = node 
      self.tail = node
      node.link = self.head
      return
    elif prev is None:
      node.link = self.head
      self.head = node
      return
    pprev, prev = self.find(prev) 
    if prev is None: 
      print("Not Exist previous node")
      return
    else:
      if prev.link == self.head: self.tail = node
      node.link = prev.link 
      prev.link = node
      
  def c_delete(self, item):
    if self.head is None: 
      print("Empty List")
      return
    prev, node = self.find(item)
    if node is None:
      print("Non Exist node")
      return
    if prev:
      prev.link = node.link
      if self.tail == node : self.tail = prev
      print("Delete complitely")
    else:
      if self.head == node:
        self.head == node.link
        print("Head delete")
      if self.tail == node:
        self.tail = self.head
    del node
  
  def find(self, item):
    temp = self.head
    prev = None
    c = 0
    while temp:
      if temp.data == item:
        return prev, temp
      prev = temp
      temp = temp.link
      c += 1
      if temp == self.head:
        print(c)
        return None, None

 


이중 연결 리스트

1. 이중 연결 리스트란 ?

  • 노드의 왼쪽, 오른쪽에 link가 존재해서 이중으로 연결되어 있음
  • 이중 연결 리스트의 head는 앞선 head 노드와는 의미가 다름
  • head 노드 : 노드의 개수를 저장, 삭제는 안됨

2. 이중 연결 리스트 구현

1) 기본 노드 구현

: 앞선 예제들과 기본 노드 구현부터 차이가 있음 -> llink, rlink 따로 존재

class Node:
  def __init__(self, item):
    self.data = item
    self.rlink = None
    self.llink = None

2) 이중 연결 리스트 연산 종류

  • 삽입 연산
  • 삭제 연산

3) 코드 구현

  • 삽입 연산 구현
    • 삽입 순서 중요
    def insertDLL(self, prev, item):
      node = Node(item)
      self.head.data += 1
      	# 데이터 개수 + 1
      if self.isEmpty():
      	# 리스트가 비어있으면 헤드와 삽입 노드가 완전히 연결
        node.llink = self.head
        node.rlink = self.head
        self.head.rlink = node
        self.head.llink = node
      else:
        prev = self.find(prev)
        	# 앞노드의 값 찾아서 앞노드를 반환
        if prev is None:
        	# 아무것도 안찾아지면
          print(" Not exist previous node data")
          return
        # 바로 아래 두 줄은 순서가 바뀌어도 상관없음
        node.llink = prev
        	# 앞노드를 node의 왼쪽 link에 연결
        node.rlink = prev.rlink
        	# 앞노드가 오른쪽 link로 연결하고 있던 뒷노드의 link를 삽입노드의 오른쪽 link에 연결 
        # 여기 바로 아래 두 줄의 순서가 매우 중요 !!!!!!
        prev.rlink.llink = node
        	# 앞노드의 오른쪽 link가 연결하고 있던 노드의 왼쪽 link에 노드를 연결한 "뒤"
        prev.rlink = node
        	# node를 앞노드의 오른쪽 link에 연결
        ```
    
  • 삭제 연산 구현
    • head는 삭제 불가
     def deleteDLL(self, item):
       if self.isEmpty():
         print("Empty List")
         return
       node = self.find(item)
       	# 삭제하려는 노드 찾아서
       if not node:
         print("not exist node")
         return
       if self.head == node:
       	# 노드가 head이면 삭제 불가
         print("head cannot be deleted")
         return;
       self.head.data -= 1
       	# 리스트 개수 -1 해주고
       node.rlink.llink = node.llink
       	# 삭제할 노드 뒤에 있는 노드의 왼쪽 링크에 삭제할 노드 앞의 노드를 연결
       node.llink.rlink = node.rlink
       	# 앞노드의 오른쪽 링크에 삭제할 노드 뒷 노드를 연결
       del node
       	# 삭제
    		```

4) 전체 코드

class Node:
  def __init__(self, item):
    self.data = item
    self.rlink = None
    self.llink = None

class DLinkedlist:
  def __init__(self):
    self.head = Node(0)
    self.head.rlink = self.head
    self.head.llink = self.head
  
  def view(self):
    temp = self.head.rlink
    print('[', end = ' ')
    while temp != self.head:
      print(temp.data, end = ' ')
      temp = temp.rlink
    print(']', end = ' ')
    if not self.isEmpty():
      print("H=", self.head.data, "R=", self.head.rlink.data, "L=",self.head.llink.data)
    else: print("Empty list")
  
  def isEmpty(self):
    return self.head.rlink == self.head
  
  def insertDLL(self, prev, item):
    node = Node(item)
    self.head.data += 1
    if self.isEmpty():
      node.llink = self.head
      node.rlink = self.head
      self.head.rlink = node
      self.head.llink = node
    else:
      prev = self.find(prev)
      if prev is None:
        print(" Not exist previous node data")
        return
      node.llink = prev
      node.rlink = prev.rlink
      prev.rlink.llink = node
      prev.rlink = node

  def deleteDLL(self, item):
    if self.isEmpty():
      print("Empty List")
      return
    node = self.find(item)
    if not node:
      print("not exist node")
      return
    if self.head == node:
      print("head cannot be deleted")
      return;
    self.head.data -= 1
    node.rlink.llink = node.llink
    node.llink.rlink = node.rlink
    del node
  
  def find(self, item):
    temp = self.head.rlink
    while temp != self.head:
      if temp.data == item:
        return temp
      temp = temp.rlink
    return None
728x90