(삽입 연산, 탐색 연산, 삭제 연산)
물리적으로 흩어져 있는 자료들을 서로 연결하여 하나로 묶는 방법
노드와 포인터로 구현한다.
노드 : 메모리의 어떤 위치에나 있을 수 있으며 다른 노드로 가기 위해서는 현재 노드가 가지고 있는 포인터를 이용하며 데이터 필드와 링크 필드로 구성되어 있다.
데이터 필드 : 저장할 데이터를 가진다.
링크 필드 : 다른 노드를 가리키는 포인터가 저장된다.
장점 : 크기가 제한되지 않고, 중간에서 쉽게 삽입하거나 삭제할 수 있는 유연한 리스트 구현이 가능하다.
데이터를 저장할 공간이 필요할 때마다 동적으로 공간을 만들어서 쉽게 추가 가능하다.
단점 : 구현이 복잡하며 임의의 항목(i번째 항목)을 추출하려고 할 때 배열을 사용하는 방법보다 시간이 많이 걸린다.
데이터와 포인터를 저장해야 하므로 메모리 공간을 많이 사용한다.
단순 연결 리스트 : 하나의 방향으로만 연결되어 있는 연결 리스트이다. 체인(chain)이라고도 하며 마지막 노드의 링크는 NULL값을 가진다.
원현 연결 리스트 : 단순 연결 리스트와 동일하며 단, 마지막 노드의 링크가 첫 번째 노드를 가리킨다.
이중 연결 리스트 : 각 노드마다 2개의 링크가 존재하며 하나의 링크는 앞에 있는 노드를 다른 하나의 링크는 뒤에 있는 노드를 가리킨다.
class Node<E> {
private E data;
private Node<E> next;
// 노드 생성자
Node(E data, Node<E> next) {
this.data = data;
this.next = next;
}
}
private Node<E> head; // 머리 노드
private Node<E> crnt; // 선택 노드
// LinkedList<E>의 생성자
public LinkedList() {
head = crnt = null;
}
public void addFirst(E obj) {
Node<E> ptr = head;
head = crnt = new Node<E>(obj, ptr);
}
public void addLast(E obj) {
if (head == null)
addFirst(obj);
else {
Node<E> ptr = head;
while (ptr != null)
ptr = ptr.next;
ptr.next = crnt = new Node<E>(obj, null);
}
}
public E search(E obj, Comparator<? super E> c) {
Node<E> ptr = head; // 첫번째 노드부터 탐색
while (ptr != null) {
if (c.compare(obj, ptr.data) == 0) { // 검색 성공
crnt = ptr;
return ptr.data;
}
ptr = ptr.next; // 다음 노드 선택
}
return null; // ptr이 비어있다면 null이라면 검색 실패
}
public void remove(Node<E> p) {
if(head!=null) {
if(p==head)
removeFirst();
else {
Node<E> ptr=head;
while(ptr.next!=p) {
ptr=ptr.next;
if(ptr==null) return; //p가 리스트에 없는 경우
}
ptr.next=p.next;
crnt=ptr;
}
}
}
연결리스트를 순회할 때 두 개의 포인터를 동시에 사용하는 기법이다. 이때 한 포인터가 다른 포인터보다 앞서도록 한다. 앞선 포인터가 따라오는 포인터보다 항상 지정된 개수만큼을 앞서도록 할 수도 있고, 아니면 따라오는 포인터를 여러 노드를 한 번에 뛰어넘도록 설정할 수도 있다.
다음 코드 참고
꼬리노드를 삭제하는 removeLast() 메서드
리스트가 비어있지 않은 상태에서 만약 노드가 1개 뿐이라면 removeFirst()메서드를 사용하여 삭제하고
그렇지 않다면 꼬리노드를 탐색할 ptr과 ptr바로 앞의 노드를 가리킬 pre를 생성하고 꼬리노드를 찾으면
꼬리노드 앞의 노드인 pre의 다음 노드 pre.next가 null을 가리키도록 설정하여
pre를 꼬리 노드로 설정한다.
public void removeLast() {
if (head != null) {
if (head.next == null)
removeFirst();
else {
Node<E> ptr = head;
Node<E> pre = head;
while (ptr != null) {
pre = ptr;
ptr = ptr.next;
}
pre.next = null;
crnt = pre;
}
}
}