[자료구조] 배열, 링크드 리스트
배열
노타빌리티에서 직접 그려본 하찮고 귀여운 내 그림...
특징
- python에서 '리스트' 라는 추상적 자료형을 구현한 대표적인 예시
- 배열에 저장되는 값들은 순서를 나타내는 번호(인덱스)를 가진다.
- 같은 종류의 데이터를 효율적으로 관리해야 하는 경우에 사용
구현
mylist = [1, 2, 3, 4, 5]
# 조회
print(mylist[0]) # 1
# 삽입
mylist.append(6) # [1, 2, 3, 4, 5, 6] - 맨 뒤에 원소 삽입
mylist.insert(3, 10) # [1, 2, 3, 10 , 4, 5, 6] - 특정 인덱스에 원소 삽입
# 삭제
del mylist[3] # [1, 2, 3, 4, 5, 6] - 인덱스로 삭제
mylist.remove(6) # [1, 2, 3, 4, 5] - 값으로 삭제
mylist.pop() # [1, 2, 3, 4] - 매개변수 입력 않을 시 맨 마지막 값(-1) 삭제
⭕️ 장점
- 배열 내의 특정 값을 조회할때 간편하다.
❌ 단점
- 자료의 삽입/삭제가 번거롭다.
연결 리스트 (링크드 리스트)
특징
- python에서 '리스트' 라는 추상적 자료형을 구현한 또 다른 예시
- 여러 개의 '노드'를 저장하는 방식으로 구현한다. 각 노드는 자신의 다음 순서의 노드를 가리킨다.
- 노드는 저장하는 값 자체를 의미하는 '자료'와 다음 노드를 가리키는 '포인터'로 구성되어 있다.
구현
# 노드 구현
class Node:
def __init__(self, data, next):
self.data = data
self.next = next
node1 = Node("hi")
node2 = Node(1120)
node3 = Node("merong")
# 노드 연결
node1.next = node2
node2.next = node3
# 링크드리스트 구현
class LinkedList:
def __init__(self) :
self.start = None # 시작 정점
self.end = None # 끝 정점
# 연결리스트에 아무런 정점도 들어있지 않은 상태. 배열에서 myList=[]와 같은 의미
### 조회
def getNode(self, pos): # pos에 위치하는 노드 조회
if pos < 0:
return None
node = self.start
# 시작 정점부터 순차적으로 보기 위해 시작 정점을 넣어줌
while pos > 0 and node != None:
# pos가 0보다 크고 node가 존재할 경우에 반복
node = node.next
# 시작 정점부터 순차적으로 검사
pos -= 1
# pos = 0이 되면 해당값에 도달.
return node # 해당값 return
def getList(self) : # 링크드리스트를 배열로 return
result = []
current = self.start
while current != None:
result.append(current.data)
current = current.Next
return result
### 삽입
def addFront(self, data) : # 맨 앞에 삽입
### 연결리스트가 비어있는 경우
if self.start == None and self.end == None:
elem = Node(data, None)
# 다음값이 없기에 포인터는 None
self.start = elem
self.end = elem
# 첫번째 값이기 때문에 시작 정점과 끝 정점은 동시에 elem이 들어감
### 연결리스트가 비어있지 않은 경우
### 왼쪽으로 삽입되는 경우, 삽입되는 값이 새로운 시작 정점이 된다.
else:
elem = Node(data, self.start)
# 따라서 다음 값을 가리키는 포인터에는 self.start를 넣는다.
self.start = elem
# 시작 정점을 새로운 값이 차지
def addBack(self, data) : # 맨 뒤에 삽입
### 비어있는 경우 (addLeft와 동일)
if self.start == None and self.end == None:
elem = Node(data, None)
self.start = elem
self.end = elem
### 비어있지 않은 경우
### 오른쪽으로 삽입되는 경우, 제일 끝에 들어가므로 다음값은 존재하지 않음
else:
elem = Node(data, None)
# 따라서 다음 값을 가리키는 포인터는 None
self.end.Next = elem
# 기존 끝 정점의 next에 elem 넣어주기
self.end = elem
#링크드리스트의 마지막을 새로운 값이 차지
def addNode(self, pos, data): # 원하는 위치(pos)에 삽입
prev = self.getNode(pos - 1) # 추가하려는 위치 바로 앞의 노드
if prev == None:
# 맨 앞에 추가하는 경우
self.start = Node(data, self.start)
# 현재 값이 시작 정점 차지. (next값은 원래 시작 정점)
else:
node = Node(data, prev.next)
# '기존 prev의 다음 위치를 가리키는 포인터'를 가진 노드 추가
prev.next = node
# prev의 next는 node(추가한 노드)를 가리키도록 한다.
### 삭제
def deleteNode(self, dataToDelete):
node = self.start
start = node
prev = None # 시작 정점부터 보기 때문에 이전 값은 아직 None
while node: # 시작 정점부터 순차적으로 반복문 시작
if node.data == dataToDelete:
# Node의 값이 지우려는 값일 때
if prev == None:
# 지우려는 Node가 시작정점이여서 앞에 아무것도 없을 때
self.start = node.next
# 본인만 지우니 다음 값이 시작 정점이 된다.
else:
# 지우려는 Node가 시작정점이 아닐 때 (=앞에 prev가 있을 때)
# 앞, 뒤 연결해주고, 사이 연결 끊기
prev.next = node.next
# 이전 노드와 현재값의 다음 노드 연결(앞-뒤 연결)
if prev.next == None:
# 이전 노드의 다음 값이 없다면 (=이전 노드가 끝 정점이 되었다면)
self.end = prev
# prev를 끝 정점으로 지정
prev = node
node = node.next # prev, node를 각각 다음 값으로 넘겨서 계속 반복
return start
⭕️ 장점
- 자료의 삽입/삭제가 간편하다.
❌ 단점
- 특정 위치의 자료를 조회할 때 번거롭다.
(배열은 찾는 자료의 위치와 관계없이 항상 단번에 값을 찾을 수 있지만, 링크드 리스트는 찾는 자료의 위치가 시작점으로부터 멀수록 연산 횟수가 많아진다.)
배열과 링크드 리스트의 차이
배열: 순차적으로 연결된 공간에 데이터를 나열하는 구조
링크드 리스트: 각각 떨어져 있는 별도의 데이터들을 임의로 연결하는 구조
-> 전체 요소를 순회하는 연산 또한 메모리 특성 상 배열이 더 유리하다.
Author And Source
이 문제에 관하여([자료구조] 배열, 링크드 리스트), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@yoon_0/자료구조-배열-링크드-리스트저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)