📌 선형 리스트(ArrayList)
선형 리스트란 배열과 같이 연속되는 기억 장소에 저장되는 리스트를 말한다. 선형 리스트는 논리적인 순서와 기억 장소에 저장되는 물리적 순서가 일치한다.
선형 리스트의 장점
- 간단한 자료구조이다.
- 접근 속도가 빠르다.
- 연속된 메모리 공간에 존재하기 때문에 관리하기가 편하다.
선형 리스트의 단점
- 중간에 자료를 삽입하기 위해서는 연속된 빈 공간이 있어야 한다.
- 즉 삽입과 삭제를 위해서는 자료의 이동이 필요하기 때문에 번거롭다.
- 또한 배열의 크기보다 데이터의 수가 클 경우 데이터를 저장할 수 없는 경우가 생긴다.
📌 연결 리스트(LinkedList)
연결 리스트는 자료들을 연속적으로 배열시키지는 않고 임의의 기억공간에 기억시키면서, 자료 항목의 순서에 따라 노드의 포인터 부분을 이용하여 서로 연결시킨 자료 구조이다.
연결 리스트의 장점
- 노드의 삽입, 삭제 작업이 용이하다.
- 기억공간이 연속적으로 놓여 있지 않아도 지정이 가능하다.
- 트리를 표현할 때 적합하다.
연결 리스트의 단점
- 항목 접근이 오래 걸린다. (첫 항목부터 순차적으로 접근하므로 최악의 경우 시간 복잡도 O(n)이 소모된다.
- 물리적으로 인접한 메모리에 위치해 있지 않다. (선형 리스트에 비해 항목들이 물리적으로 인접해있지 않아 접근 시간 단축과 캐싱에 불리하다.)
- 참조 포인터를 위한 메모리 공간이 낭비된다.
📖 Kotlin 코드로 연결 리스트 구현
LinkedList 클래스는 연결 리스트의 전체적인 로직이 구현된 클래스로 내부 클래스인 Node와 여러 가지 기능 메서드 함수를 포함하고 있다.
LinkedList 클래스
class LinkedList constructor(var videoList: ArrayList<Video>){
inner class Node{
var data: Any? = null // 데이터가 저장될 필드
var next: Node? = null // 다음 노드를 가리키는 필드
}
var head: Node? = null
var tail: Node? = null
var size: Int = 0
// 특정 위치의 노드를 찾아내는 함수
fun find(index: Int): Node? {
var node = head
for (i in 0 until index) {
node = node?.next ?: error("invalid node") // 엘비스 표현법
}
return node
}
// data 를 받아서 그 위치 index 를 찾아내는 함수
fun findIndex(data: Any): Int{
var index = 0
var node = head
for (i in 0 until 13){
if (node?.data == data){
index = i // 찾던 id 값을 찾은 경우의 index
break
} else {
node = node?.next
continue
}
}
return index // index 값 리턴
}
fun addFirst(data: Any){
val newNode = Node().apply {
this.data = data
this.next = head // 새로운 노드의 다음 노드로 헤드를 지정
}
head = newNode // 헤드로 새로운 노드를 지정
if(head?.next == null){
tail = head
}
size++
}
fun addLast(data: Any){
if(size == 0){
addFirst(data) // 리스트에 노드가 없다면 addFirst 메서드 실행
} else {
val newNode = Node().apply{
this.data = data
}
tail?.next = newNode // 마지막 노드의 다음 노드로 생성한 노드 지정
tail = newNode // 마지막 노드 갱신
size++
}
}
fun addAt(index: Int, data: Any){
if(index == 0){
addFirst(data)
} else {
val newNode = Node().apply {
this.data = data
}
val node = find(index)!!
val temp = node.next
newNode.next = temp // 집어 넣을 새로운 노드의 다음 노드에 temp
node.next = newNode // 찾은 index 의 다음 노드에 새로운 노드 집어 넣기
if (newNode.next == null){
tail = newNode
}
size++
}
}
fun removeFirst(): Any {
val node = head
head = node?.next
size--
return node?.data ?: error("invalid data")
}
fun removeAt(index: Int): Any {
if (index == 0){
return removeFirst()
} else {
val temp = find(index - 1)
val deletedNode = temp?.next
temp?.next = temp?.next?.next
val returnData = deletedNode?.data ?: error("invalid data")
if(deletedNode == tail){
tail = temp
}
size--
return returnData
}
}
}
대표로 addFirst, addAt, removeAt에 대해 간략히 설명해 보자면
addFirst 메서드는 Any 타입의 데이터를 매개변수로 받아와 헤드로 새로운 노드를 지정하고 만약 헤드의 다음 노드가 없다면 즉 링크드 리스트에 아무것도 없다면 헤드와 테일을 같게 만들어 준다.
addFirst 메서드
fun addFirst(data: Any){
val newNode = Node().apply {
this.data = data
this.next = head // 새로운 노드의 다음 노드로 헤드를 지정
}
head = newNode // 헤드로 새로운 노드를 지정
if(head?.next == null){
tail = head
}
size++
}
addAt 메서드는 Any 타입의 데이터와 Int 타입의 인덱스를 매개변수로 받아와 집어넣은 새로운 노드의 다음 노드를 temp로 지정하고 찾은 index의 다음 노드에 새로운 노드를 집어넣는 방식으로 구현한다.
addAt 메서드
fun addAt(index: Int, data: Any){
if(index == 0){
addFirst(data)
} else {
val newNode = Node().apply {
this.data = data
}
val node = find(index)!!
val temp = node.next
newNode.next = temp // 집어 넣을 새로운 노드의 다음 노드에 temp
node.next = newNode // 찾은 index 의 다음 노드에 새로운 노드 집어 넣기
if (newNode.next == null){
tail = newNode
}
size++
}
}
removeAt 메서드는 만약 노드가 하나밖에 없다면 구현해 놓은 removeFirtst 함수를 실행시키고 그게 아니라면 index - 1 번째 노드를 temp라고 임시 지정하고 난 뒤 삭제할 노드의 앞 노드를 삭제할 노드의 뒤의 노드와 연결시켜 주어 노드가 삭제되더라도 연결 리스트가 유지되도록 한다.
removeAt 메서드
fun removeAt(index: Int): Any {
if (index == 0){
return removeFirst()
} else {
val temp = find(index - 1) // k-1 번째 노드를 temp 의 값으로 지정한다.
val deletedNode = temp?.next
temp?.next = temp?.next?.next // 삭제할 노드의 앞의 노드를 삭제할 노드의 뒤의 노드와 연결시켜 준다.
val returnData = deletedNode?.data ?: error("invalid data")
if(deletedNode == tail){
tail = temp
}
size--
return returnData
}
}
Reference:
https://coding-factory.tistory.com/228
https://bluejake.tistory.com/44
https://2dubbing.tistory.com/53
https://supermemi.tistory.com/67
'CS' 카테고리의 다른 글
JVM 메모리 구조 (0) | 2022.01.19 |
---|---|
가상머신에 리눅스 설치 & 로컬 컴퓨터로 리모트 컴퓨터 접속 (0) | 2022.01.06 |
OAuth 개념 및 동작 방식 (0) | 2021.10.27 |
CI & CD란 (Jenkins, Gitlab CI/CD, Travis) (0) | 2021.10.19 |
쿠키(cookie) 세션(session) 토큰(token)(JWT) 그리고 캐시(cache) (0) | 2021.10.15 |