링크드 리스트 (Linked List), 대학교의 자료 구조 수업을 듣기 시작하면 무조건, 반드시, 꼭 한번 들어보는 녀석입니다. 그리고 반드시 구현 과제를 내곤 하죠! 대체 뭔데 이렇게 중요하게 다룰까요? 대체 뭐하는 녀석인지, 어떻게 만드는지 한 번 알아봅시다.
링크드 리스트 (연결 리스트, Linked List) 란?
"연결 리스트, 링크드 리스트(linked list)는 각 노드가 데이터와 포인터를 가지고 한 줄로 연결되어 있는 방식으로 데이터를 저장하는 자료 구조이다. 이름에서 말하듯이 데이터를 담고 있는 노드들이 연결되어 있는데, 노드의 포인터가 다음이나 이전의 노드와의 연결을 담당하게 된다. 연결 리스트의 종류로는 단일 연결 리스트, 이중 연결 리스트 등이 있다.
연결 리스트는 늘어선 노드의 중간지점에서도 자료의 추가와 삭제가 O(1)의 시간에 가능하다는 장점을 갖는다. 그러나 배열이나 트리 구조와는 달리 특정 위치의 데이터를 검색해 내는데에는 O(n)의 시간이 걸리는 단점도 갖고 있다."
위에서 얘기한 것을 보면 연결 리스트엔 2가지 타입이 존재합니다.
- 단일 연결 리스트 : 한 방향으로만 연결된 리스트
- 이중 연결 리스트 : 양 방향으로 연결된 리스트
이 포스팅에서는 단일 연결 리스트가 어떻게 생긴 것인지, 또 어떻게 구현하는 것인지 학습해 볼 예정입니다. 물론 이중 연결 리스트는 다른 포스팅에서 소개할 것입니다.
단일 연결 리스트 구조
노드에는 개발자가 원하는 여러가지 데이터를 담을 수 있는데, 뭐 숫자를 넣어도 좋고, 문장(String)을 넣어도 좋습니다. 필요한 것을 넣으세요! 이렇게 노드를 줄줄이 소세지처럼 엮은 것이 연결 리스트입니다. 아래의 그림과 같이 말이죠.
그런데 이렇게 만들고보니, 우리는 가장 처음 노드를 어떤 노드로 할 것인지 정하지 않았습니다. 노드를 만들어서 연결을 해야하는데, 어떤 노드부터 시작해야 되는지 모르는 것이죠. 그냥 아무 노드 하나 만들어서 거기서부터 쭉쭉 연결하면 안 되냐구요? 맞습니다. 우리는 그 아무 노드를 헤더 (header) 라는 조금 다른 이름으로 부르기 시작하죠.
이렇게 만들면 맨 처음 연결 리스트를 구현할 때 가장 우선적으로 헤더 노드를 만들어놓고 원하는 형태의 노드를 뒤에 붙이는 식으로 구현하기만 하면 끝입니다.
연결 리스트 구현하기
개념은 무척 간단해서 후딱 지나간 느낌이 없잖아 있는데, 코딩의 어려움은 머릿속에 있는 내용을 코드로 표현하는 것이죠. 어떻게 만들어야 할까요? 아래의 순서를 따라와 보세요.
static class Node {
String data; // 데이터는 원하는 것을 넣어주시면 됩니다.
Node next;
public Node(String data) { this.data = data; }
}
Node header = new Node("header");
class SinglyLinkedList {
Node header = new Node("header");
int size; // 연결 리스트에 들어있는 노드의 개수를 따로 저장합니다. (순회하기 편하려고)
}
// 맨 앞에 노드 붙이기 (즉, 헤더 바로 다음에 붙이기)
public static void addFirst(Node node) {
node.next = header.next;
header.next = node;
size++;
}
public static void addLast(Node node) {
Node curr = header;
while (curr.next != null) {
curr = curr.next;
}
curr.next = node;
size++;
}
// idx번째 노드 앞에 붙이기
public static void add(Node node, int idx) {
if (idx > size) return;
if (idx == 0) { addFirst(node); return; }
// 헤더부터 시작해서 idx번째 노드 찾기
int cnt = -1;
Node curr = header;
while (curr.next != null) {
// 다음 노드 탐색
curr = curr.next;
// 찾고자 하는 위치에 도달하면 탐색 종료
if (++cnt == idx - 1) break;
}
node.next = curr.next;
curr.next = node;
size++;
}
public static void removeFirst() {
header.next = header.next.next;
size--;
}
public static void removeLast() {
Node curr = header;
if (curr.next == null) return;
while (curr.next.next != null) {
curr = curr.next;
}
curr.next = null;
size--;
}
public static void remove(int idx) {
if (idx > size) return;
if (idx == 0) { removeFirst(); return; }
int cnt = -1;
// 헤더부터 시작해서 idx번째 노드 찾기
Node curr = header;
while (curr != null) {
// 다음 노드 탐색
curr = curr.next;
// 찾고자 하는 위치에 도달하면 탐색 종료
if (++cnt == idx - 1) break;
}
curr.next = curr.next.next;
size--;
}
마치며..
class Node {
String data; // 데이터는 원하는 것을 넣어주시면 됩니다.
Node next;
public Node(String data) { this.data = data; }
}
class SinglyLinkedList {
Node header = new Node("header");
int size; // 연결 리스트에 들어있는 노드의 개수를 따로 저장합니다. (순회하기 편하려고)
// 맨 앞에 노드 붙이기 (즉, 헤더 바로 다음에 붙이기)
public void addFirst(Node node) {
node.next = header.next;
header.next = node;
size++;
}
// idx번째 노드 앞에 붙이기
public void add(Node node, int idx) {
if (idx > size) return;
if (idx == 0) { addFirst(node); return; }
// 헤더부터 시작해서 idx번째 노드 찾기
int cnt = -1;
Node curr = header;
while (curr.next != null) {
// 다음 노드 탐색
curr = curr.next;
// 찾고자 하는 위치에 도달하면 탐색 종료
if (++cnt == idx - 1) break;
}
node.next = curr.next;
curr.next = node;
size++;
}
public void addLast(Node node) {
Node curr = header;
while (curr.next != null) {
curr = curr.next;
}
curr.next = node;
size++;
}
public void removeFirst() {
header.next = header.next.next;
size--;
}
public void remove(int idx) {
if (idx > size) return;
if (idx == 0) { removeFirst(); return; }
int cnt = -1;
// 헤더부터 시작해서 idx번째 노드 찾기
Node curr = header;
while (curr != null) {
// 다음 노드 탐색
curr = curr.next;
// 찾고자 하는 위치에 도달하면 탐색 종료
if (++cnt == idx - 1) break;
}
curr.next = curr.next.next;
size--;
}
public void removeLast() {
Node curr = header;
if (curr.next == null) return;
while (curr.next.next != null) {
curr = curr.next;
}
curr.next = null;
size--;
}
public void print() {
Node curr = header;
while (curr != null) {
System.out.printf(curr.data + " ");
curr = curr.next;
}
System.out.println("");
}
public static void main(String[] args) {
SinglyLinkedList linkedList = new SinglyLinkedList();
linkedList.print();
linkedList.addFirst(new Node("1"));
linkedList.print();
linkedList.addFirst(new Node("2"));
linkedList.print();
linkedList.addFirst(new Node("3"));
linkedList.print();
linkedList.addFirst(new Node("4"));
linkedList.print();
linkedList.addFirst(new Node("5"));
linkedList.print();
linkedList.add(new Node("6"), 2);
linkedList.print();
linkedList.add(new Node("7"), 0);
linkedList.print();
linkedList.add(new Node("10"), 6);
linkedList.print();
linkedList.add(new Node("71"), 8);
linkedList.print();
linkedList.add(new Node("22"), 1);
linkedList.print();
linkedList.removeFirst();
linkedList.print();
linkedList.removeLast();
linkedList.print();
linkedList.remove(0);
linkedList.print();
linkedList.remove(3);
linkedList.print();
linkedList.remove(5);
linkedList.print();
linkedList.remove(2);
linkedList.print();
}
}
댓글
댓글 쓰기