연결 리스트에는 단순, 원형, 이중 연결리스트 등이 존재합니다. 오늘은 이 중 첫 번째인 단순 연결 리스트를 구현해보도록 하겠습니다.
1. 노드 생성
우선 제일 먼저 할 일은 노드를 생성하는 부분을 구현하는 것 입니다. 지난 포스트에서 소개한 노드의 구조를 보면 다음과 같이 데이터와 링크 필드 두가지로 구현되어 있습니다.
public class LinkedList {
private class Node {
//노드
private Object data; //데이터 필드
private Node next; //링크 필드
public Node(Object input) {
this.data = input;
this.next = null;
}
}
//첫 번째 노드
private Node head;
//마지막 노드
private Node tail;
//리스트의 크기 = 노드 갯수
private int sizeOfList = 0;
}
class Node에서 노드를 생성하고 데이터를 담습니다. 그 이후에 오는 private 변수 세 개는 리스트 구현에서 활용될 LinkedList 클래스의 멤버변수들 입니다.
2. 노드 삽입
2-1. 리스트의 처음에 노드 삽입하기
우선 리스트의 첫 부분(머리)에 노드를 삽입하는 메서드입니다.
public void insertFirst(Object input) {
Node newNode = new Node(input);
//기존 head 노드를 새 노드의 다음으로 지정
newNode.next = head;
//head를 새로 생성한 노드로 지정
head = newNode;
sizeOfList++;
if(head.next == null) {
//1칸 짜리 리스트면 head는 tail이 된다.
tail = head;
}
}
2-2. 리스트의 중간에 노드 삽입하기
리스트의 중간 부분에 노드를 삽입하는 것은 처음이나 끝부분에 비해서 살짝 추가적인 과정을 요구합니다.
public Node node(int idx) {
Node n = head;
for (int i = 0; i < idx; i++) {
n = n.next;
}
return n;
}
public void insert(int idx, Object input) {
if (idx == 0) {
insertFirst(input);
}
else {
Node temp1 = node(idx - 1);
Node temp2 = temp1.next;
Node newNode = new Node(input);
temp1.next = newNode;
newNode.next = temp2;
sizeOfList++;
if (newNode.next == null) {
tail = newNode;
}
}
}
살짝 뜯어보기로 합시다.
public Node node(int idx) {
Node n = head;
for (int i = 0; i < idx; i++) {
//idx위치까지의 노드를 n에 덮어씌우며 저장
n = n.next;
}
//idx위치의 노드 n을 반환
return n;
}
이 부분은 리스트에서 특정 노드의 위치를 찾는 메소드입니다. 중간에 삽입하기 위해서는 이전의 노드를 찾아야겠죠. 사용자로부터 원하는 위치(idx)를 입력받으면 그 위치까지 for문을 통해 찾아갑니다.
public void insert(int idx, Object input) {
//idx가 0, 리스트가 비어있으면 머리에 삽입
if (idx == 0) {
insertFirst(input);
}
else {
//이전 노드를 저장할 임시 변수 temp1
Node temp1 = node(idx - 1);
//temp1의 링크 필드가리키는 노드를 임시로 저장할 변수 temp2
//이 노드가 idx번째의 노드
Node temp2 = temp1.next;
Node newNode = new Node(input);
//기존 노드의 링크필드를 새로 생성한 노드를 가리키도록 설정
temp1.next = newNode;
//새 노드의 링크필드가 다음 노드를 가리키도록 설정
newNode.next = temp2;
sizeOfList++;
if (newNode.next == null) {
tail = newNode;
}
}
}
이 부분이 중간에 삽입하는 메소드입니다. 글보다는 그림이해가 빠르실 것 같습니다.
이처럼 이전 노드와 지정한 위치의 노드를 빼놨다가 그 사이에 새 노드를 삽입하는 작업을 마친 후 다시 이어줍니다. 이것이 연결 리스트 노드의 중간 삽입입니다.
2-3. 리스트 마지막에 노드 삽입하기
public void insertLast(Object input) {
if (sizeOfList == 0) {
insertFirst(input);
}
else {
Node newNode = new Node(input);
//기존 tail노드가 새 노드를 가리키도록 설정
tail.next = newNode;
//tail을 새로 생성한 노드를 가리키도록 설정
tail = newNode;
sizeOfList++;
}
}
꼬리 부분에 삽입하는 과정은 처음과 중간 삽입에 비해서 비교적 간단합니다.
3. 노드 삭제
3-1. 리스트의 처음 노드 삭제하기
public void removeFirst() {
//head를 두 번째 노드가 차지하도록 변경
head = head.next;
sizeOfList--;
}
처음 부분의 노드를 삭제하는 것은 매우 간단합니다. 그냥 두번째 노드가 head를 나타내게 하면 됩니다.
3-2. 리스트의 중간 노드 삭제하기
public void remove(int idx){
if(idx == 0) {
removeFirst();
}
else {
//삭제 이전 노드를 temp에 저장
Node temp = node(idx-1);
//현재 노드(=삭제할 노드)를 임시로 저장;
Node tempDeleteNode = temp.next;
//temp가 삭제 노드 다음을 가리키도록 설정
temp.next = temp.next.next;
//삭제 노드가 마지막였다면 temp가 tail이 됩니다.
if(tempDeleteNode == tail) {
tail = temp;
}
tempDeleteNode = null;
sizeOfList--;
}
}
삽입 메소드에서 이용했던 node()메소드(특정 위치를 찾는 메소드)를 여기서 다시 한 번 사용합니다. 삭제는 간단한 것이 그냥 이전 노드(temp)가 삭제 노드의 링크 필드가 가리키는 노드를 가리키도록 하면 됩니다.
이 과정이 temp.next = temp.next.next; 문장으로 수행됩니다.
3-3. 리스트의 마지막 노드 삭제하기
public void removeLast() {
if(sizeOfList == 1){
removeFirst();
}
else {
//tail 바로 앞의 노드를 저장하는 temp변수
Node temp = node(sizeOfList - 2);
//temp의 링크 필드를 비웁니다.
temp.next = null;
//tail을 temp로 설정하면 끝
tail = temp;
sizeOfList--;
}
}
마지막 부분의 삭제도 간단합니다. tail 이전의 노드를 가져와서 그 노드를 tail로 설정하기만 하면 됩니다.
4. 리스트에서 검색하기
자료구조의 주 기능인 검색입니다. 이 부분이 핵심 기능이라고도 할 수 있죠. 검색에도 여러 방식이 있겠지만 인덱스로 검색하는 방식을 다뤄보겠습니다.
public Node search(int idx){
int i = 0;
//검색 결과를 담기위한 변수 node
//head,즉 처음 노드로 초기화 저장
Node node = head;
//idx에 도달할때 까지 반복
while(i != idx) {
//노드에 다음 노드를 저장
node = node.next;
i++;
}
//while문 종료 후 node에 저장되어있는 노드 반환
return node;
}
검색 하는 핵심 부분은 while문 부분입니다. i가 idx와 같지 않을 때 까지, 즉 찾는 위치의 바로전 노드 까지 반복합니다. 이러면 node에는 node.next가 저장되어 우리가 원하는 노드를 찾을 수 있습니다.
5. 전체 코드
public class LinkedList {
private class Node {
private Object data;
private Node next;
public Node(Object input) {
this.data = input;
this.next = null;
}
}
private Node head;
private Node tail;
private int sizeOfList = 0;
public void insertFirst(Object input) {
Node newNode = new Node(input);
newNode.next = head;
head = newNode;
sizeOfList++;
if (head.next == null) {
tail = head;
}
}
public Node node(int idx) {
Node n = head;
for (int i = 0; i < idx; i++) {
n = n.next;
}
return n;
}
public void insert(int idx, Object input) {
if (idx == 0) {
insertFirst(input);
}
else {
Node temp1 = node(idx - 1);
Node temp2 = temp1.next;
Node newNode = new Node(input);
temp1.next = newNode;
newNode.next = temp2;
sizeOfList++;
if (newNode.next == null) {
tail = newNode;
}
}
}
public void insertLast(Object input) {
if (sizeOfList == 0) {
insertFirst(input);
}
else {
Node newNode = new Node(input);
tail.next = newNode;
tail = newNode;
sizeOfList++;
}
}
public void removeFirst() {
head = head.next;
sizeOfList--;
}
public void remove(int idx){
if(idx == 0) {
removeFirst();
}
else {
Node temp = node(idx-1);
Node tempDeleteNode = temp.next;
temp.next = temp.next.next;
if(tempDeleteNode == tail) {
tail = temp;
}
tempDeleteNode = null;
sizeOfList--;
}
}
public void removeLast() {
if(sizeOfList == 1){
removeFirst();
}
else {
Node temp = node(sizeOfList - 2);
temp.next = null;
tail = temp;
sizeOfList--;
}
}
public Node search(int idx){
int i = 0;
Node node = head;
while(i != idx) {
node = node.next;
i++;
}
return node;
}
}
참조
https://opentutorials.org/module/1335/8857
https://freestrokes.tistory.com/84
'Programming > 자료구조' 카테고리의 다른 글
연결 리스트 Linked List (0) | 2021.09.03 |
---|---|
자료구조 다시 시작하기 (0) | 2021.08.27 |
[Data Structure] 연결 리스트(Linked List) (0) | 2021.06.25 |
[Data Structure] 선형 리스트 (Linear List) (0) | 2021.06.24 |
[Data Structure] 리스트 (List) (0) | 2021.06.24 |
댓글