1. 링크드 리스트 (Linked List) 구조
- 연결 리스트라고도 함
- 배열은 순차적으로 연결된 공간에 데이터를 나열하는 데이터 구조
- 링크드 리스트는 떨어진 곳에 존재하는 데이터를 화살표로 연결해서 관리하는 데이터 구조
- 링크드 리스트 기본 구조와 용어
- 노드(Node): 데이터 저장 단위(데이터 값, 포인터)로 구성
- 포인터(pointer): 각 노드 안에서, 다음이나 이전의 노드와의 연결 정보를 가지고 있는 공간
2. 간단한 링크드 리스트 예
- 최대한 간단한 형태로 코드를 작성해보며 링크드 리스트를 이해해보기
2-1. Node 클래스 구현
// src/com.company/Node.java
package com.company;
// Node 클래스 구현
public class Node<T> {
private T data;
// null을 가리키고 있음
public Node<T> next = null;
public Node(T data) {
// set-data
this.data = data;
}
}
2-2. Node와 Node 연결하기: Node 인스턴스간
// src/com.company/Main.java
package com.company;
public class Main {
public static void main(String[] args) {
Node<Integer> node1 = new Node<Integer>(1);
Node<Integer> node2 = new Node<Integer>(2);
node1.next = node2;
Node<Integer> head = node1;
}
}
2-3. 링크드 리스트에 데이터 추가하기
// src/com.company/SingleLinkedList.java
package com.company;
public class SingleLinkedList<T> {
// init SingleLinkedList's head for 'null'
public Node<T> head = null;
// Node
public class Node<T> {
private T data;
public Node<T> next = null;
public Node(T data) {
this.data = data;
}
}
// add One Node
public void addNode(T data) {
// if head points nothing
if(head == null) {
// head is new Node
head = new Node<T>(data);
} else {
// if has head
// head -> node -> node -> null
// -> (node) <-
// using while to go null
Node<T> node = this.head;
while(node.next != null) {
node = node.next;
}
// head -> node -> node -> node -> null
// -> (add this node) <-
node.next = new Node<T>(data);
}
}
}
// src/com.company/Main.java
package com.company;
public class Main {
public static void main(String[] args) {
SingleLinkedList<Integer> MyLinkedList = new SingleLinkedList<Integer>();
MyLinkedList.addNode(1);
MyLinkedList.addNode(2);
System.out.println(MyLinkedList.head.next.data);
}
}
// 2
2-4. 링크드 리스트 데이터 출력하기
// src/com.company/SingleLinkedList.java
package com.company;
public class SingleLinkedList<T> {
// init SingleLinkedList's head for 'null'
public Node<T> head = null;
// Node
public class Node<T> {
public T data;
public Node<T> next = null;
public Node(T data) {
this.data = data;
}
}
// add One Node
public void addNode(T data) {
// if head points nothing
if(head == null) {
// head is new Node
head = new Node<T>(data);
} else {
// if has head
// head -> node -> node -> null
// -> (node) <-
// using while to go null
Node<T> node = this.head;
while(node.next != null) {
node = node.next;
}
// head -> node -> node -> node -> null
// -> (add this node) <-
node.next = new Node<T>(data);
}
}
public void printAll() {
// if SingleLinkedList has head
if(head != null) {
Node<T> node = this.head;
System.out.println(node.data);
// cycle to print all value
while(node.next != null) {
node = node.next;
System.out.println(node.data);
}
}
}
}
// src/com.company/Main.java
package com.company;
public class Main {
public static void main(String[] args) {
SingleLinkedList<Integer> MyLinkedList = new SingleLinkedList<Integer>();
MyLinkedList.addNode(1);
MyLinkedList.addNode(2);
MyLinkedList.addNode(3);
MyLinkedList.printAll();
}
}
// 1
// 2
// 3
3. 링크드 리스트의 장단점 (전통적인 C언어에서의 배열과 링크드 리스트)
- 장점
- 미리 데이터 공간을 미리 할당하지 않아도 됨
- 배열은 미리 데이터 공간을 할당 해야 함
- 미리 데이터 공간을 미리 할당하지 않아도 됨
- 단점
- 연결을 위한 별도 데이터 공간이 필요하므로, 저장공간 효율이 높지 않음
- 연결 정보를 찾는 시간이 필요하므로 접근 속도가 느림
- 중간 데이터 삭제시, 앞뒤 데이터의 연결을 재구성해야 하는 부가적인 작업 필요
4. 링크드 리스트의 복잡한 기능1 (링크드 리스트 데이터 사이에 데이터를 추가)
(출처: wikipedia, https://en.wikipedia.org/wiki/Linked_list))
// src/com.company/SingleLinkedList.java
package com.company;
public class SingleLinkedList<T> {
// init SingleLinkedList's head for 'null'
public Node<T> head = null;
// Node
public class Node<T> {
public T data;
public Node<T> next = null;
public Node(T data) {
this.data = data;
}
}
// add One Node
public void addNode(T data) {
// if head points nothing
if(head == null) {
// head is new Node
head = new Node<T>(data);
} else {
// if has head
// head -> node -> node -> null
// -> (node) <-
// using while to go null
Node<T> node = this.head;
while(node.next != null) {
node = node.next;
}
// head -> node -> node -> node -> null
// -> (add this node) <-
node.next = new Node<T>(data);
}
}
public void printAll() {
// if SingleLinkedList has head
if(head != null) {
Node<T> node = this.head;
System.out.println(node.data);
// cycle to print all value
while(node.next != null) {
node = node.next;
System.out.println(node.data);
}
}
}
public Node<T> search(T data) {
if(this.head == null) {
return null;
} else {
Node<T> node = this.head;
while(node != null) {
if(node.data == data) {
return node;
} else {
node = node.next;
}
}
// if cannot search the data
return null;
}
}
// add data between the Node
public void addNodeInside(T data, T isData) {
// add next to the searchedNode
Node<T> searchedNode = this.search(isData);
if(searchedNode == null) {
this.addNode(data);
} else {
// add new Node after searchedNode!
// make some new node
Node<T> newNode = new Node<T>(data);
Node<T> nextNode = searchedNode.next;
newNode.next = nextNode;
searchedNode.next = newNode;
}
}
}
// src/com.company/Main.java
package com.company;
public class Main {
public static void main(String[] args) {
SingleLinkedList<Integer> MyLinkedList = new SingleLinkedList<Integer>();
MyLinkedList.addNode(1);
MyLinkedList.addNode(2);
MyLinkedList.addNode(3);
// add
MyLinkedList.addNodeInside(5, 1);
MyLinkedList.printAll();
}
}
// 1
// 5
// 2
// 3
5. 링크드 리스트의 복잡한 기능2 (특정한 노드를 삭제)
- delete를 추가
// src/com.company/SingleLinkedList.java
package com.company;
public class SingleLinkedList<T> {
// init SingleLinkedList's head for 'null'
public Node<T> head = null;
// Node
public class Node<T> {
public T data;
public Node<T> next = null;
public Node(T data) {
this.data = data;
}
}
// add One Node
public void addNode(T data) {
// if head points nothing
if(head == null) {
// head is new Node
head = new Node<T>(data);
} else {
// if has head
// head -> node -> node -> null
// -> (node) <-
// using while to go null
Node<T> node = this.head;
while(node.next != null) {
node = node.next;
}
// head -> node -> node -> node -> null
// -> (add this node) <-
node.next = new Node<T>(data);
}
}
public void printAll() {
// if SingleLinkedList has head
if(head != null) {
Node<T> node = this.head;
System.out.println(node.data);
// cycle to print all value
while(node.next != null) {
node = node.next;
System.out.println(node.data);
}
}
}
public Node<T> search(T data) {
if(this.head == null) {
return null;
} else {
Node<T> node = this.head;
while(node != null) {
if(node.data == data) {
return node;
} else {
node = node.next;
}
}
// if cannot search the data
return null;
}
}
// add data between the Node
public void addNodeInside(T data, T isData) {
// add next to the searchedNode
Node<T> searchedNode = this.search(isData);
if(searchedNode == null) {
this.addNode(data);
} else {
// add new Node after searchedNode!
// make some new node
Node<T> newNode = new Node<T>(data);
Node<T> nextNode = searchedNode.next;
newNode.next = nextNode;
searchedNode.next = newNode;
}
}
// delete value -> search value
public boolean delNode(T isData) {
if(this.head == null) {
// if Node has no data -> return false
return false;
} else {
Node<T> node = this.head;
if(node.data == isData) {
this.head = this.head.next;
return true;
} else {
while(node.next != null) {
if(node.next.data == isData) {
node.next = node.next.next;
return true;
}
node = node.next;
}
// if cannot search data
return false;
}
}
}
}
// src/com.company/Main.java
package com.company;
public class Main {
public static void main(String[] args) {
SingleLinkedList<Integer> MyLinkedList = new SingleLinkedList<Integer>();
MyLinkedList.addNode(1);
MyLinkedList.addNode(2);
MyLinkedList.addNode(3);
// add
MyLinkedList.addNodeInside(5, 1);
// delete
MyLinkedList.delNode(3);
MyLinkedList.printAll();
}
}
// 1
// 5
// 2
6. 다양한 링크드 리스트 구조: 더블 링크드 리스트 (Double linked list)
- 더블 링크드 리스트(Double linked list) 기본 구조
- 이중 연결 리스트라고도 함
- 장점: 양방향으로 연결되어 있어서 노드 탐색이 양쪽으로 모두 가능
(출처: wikipedia, https://en.wikipedia.org/wiki/Linked_list)
// src/com.company/DoubleLinkedList.java
package com.company;
public class DoubleLinkedList<T> {
public Node<T> head = null;
public Node<T> tail = null;
public class Node<T> {
public T data;
public Node<T> prev = null;
public Node<T> next = null;
public Node(T data) {
this.data = data;
}
}
public void addNode(T data) {
// if DoubleLinkedList's head is null
if(this.head == null) {
this.head = new Node<T>(data);
this.tail = this.head;
} else {
Node<T> node = this.head;
while(node.next != null) {
node = node.next;
}
// head -> node -> node -> null
// -> (point this) <-
// add node
Node<T> newNode = new Node<T>(data);
// head -> node -> node -> newNode -> null
node.next = newNode;
node.next.prev = node;
this.tail = node.next;
}
}
public void printAll() {
if(this.head != null) {
Node<T> node = this.head;
System.out.println(node.data);
while(node.next != null) {
node = node.next;
System.out.println(node.data);
}
}
}
}
// src/com.company/Main.java
package com.company;
public class Main {
public static void main(String[] args) {
DoubleLinkedList<Integer> MyLinkedList = new DoubleLinkedList<Integer>();
MyLinkedList.addNode(2);
MyLinkedList.addNode(4);
MyLinkedList.addNode(5);
MyLinkedList.addNode(8);
MyLinkedList.addNode(3);
MyLinkedList.printAll();
}
}
// 2
// 4
// 5
// 8
// 3
6-1. 기능 추가하기
- 위 코드를 기반으로 기능을 추가해보겠습니다.
- head부터 특정 노드를 찾는 메소드 추가하기
- tail부터 특정 노드를 찾는 메서드 추가
Double Linked List 최종코드
// src/com.company/DoubleLinkedList.java
package com.company;
import java.util.ArrayList;
public class DoubleLinkedList<T> {
public Node<T> head = null;
public Node<T> tail = null;
public class Node<T> {
public T data;
public Node<T> prev = null;
public Node<T> next = null;
public Node(T data) {
this.data = data;
}
}
public void addNode(T data) {
// if DoubleLinkedList's head is null
if(this.head == null) {
this.head = new Node<T>(data);
this.tail = this.head;
} else {
Node<T> node = this.head;
while(node.next != null) {
node = node.next;
}
// head -> node -> node -> null
// -> (point this) <-
// add node
Node<T> newNode = new Node<T>(data);
// head -> node -> node -> newNode -> null
node.next = newNode;
node.next.prev = node;
this.tail = node.next;
}
}
public void printAll() {
ArrayList<T> resultArray = new ArrayList<>();
if(this.head != null) {
Node<T> node = this.head;
// System.out.println(node.data);
resultArray.add(node.data);
while(node.next != null) {
node = node.next;
// System.out.println(node.data);
resultArray.add(node.data);
}
}
System.out.println(resultArray);
}
// search from Head (Node)
public Node<T> searchFromHead(T isData) {
if(this.head == null) {
return null;
} else {
Node<T> node = this.head;
while(node != null) {
if(node.data == isData) {
return node;
} else {
node = node.next;
}
}
return null;
}
}
// search from Tail (Node)
public Node<T> searchFromTail(T isData) {
if(this.head == null) {
return null;
} else {
Node<T> node = this.tail;
while(node != null) {
if(node.data == isData) {
return node;
} else {
node = node.prev;
}
}
return null;
}
}
public boolean insertToFront(T existedData, T addData) {
if(this.head == null) {
Node<T> node = new Node<T>(addData);
this.head = node;
this.tail = head;
return true;
}else {
Node<T> node = this.head;
if(node.data == existedData) {
Node<T> newHead = new Node<T>(addData);
newHead.next = this.head;
this.head = newHead;
this.head.next.prev = this.head;
return true;
} else {
while(node != null) {
// head -> node -> node -> tail
if(node.data == existedData) {
// first node
Node<T> nodePrev = node.prev;
// new Node ( for add )
Node<T> newNode = new Node<T>(addData);
// optioning next
nodePrev.next = newNode;
nodePrev.next.next = node;
//optioning prev
nodePrev.next.prev = nodePrev;
node.prev = nodePrev.next;
return true;
} else {
node = node.next;
}
}
}
return false;
}
}
}
// src/com.company/Main.java
package com.company;
public class Main {
public static void main(String[] args) {
DoubleLinkedList<Integer> MyLinkedList = new DoubleLinkedList<Integer>();
MyLinkedList.addNode(1);
MyLinkedList.addNode(2);
MyLinkedList.addNode(3);
MyLinkedList.addNode(4);
MyLinkedList.addNode(5);
MyLinkedList.printAll();
System.out.println("------------------------");
MyLinkedList.insertToFront(3, 2);
MyLinkedList.printAll();
System.out.println("------------------------");
MyLinkedList.insertToFront(6, 2);
MyLinkedList.insertToFront(1, 0);
MyLinkedList.printAll();
System.out.println("------------------------");
MyLinkedList.addNode(6);
MyLinkedList.printAll();
}
}
// [1, 2, 3, 4, 5]
// ------------------------
// [1, 2, 2, 3, 4, 5]
// ------------------------
// [0, 1, 2, 2, 3, 4, 5]
// ------------------------
// [0, 1, 2, 2, 3, 4, 5, 6]
'Algorithm > Algorithm-Java' 카테고리의 다른 글
Java-자료구조 (Hash Table) (0) | 2021.11.18 |
---|---|
Java-자료구조 (시간 복잡도) (0) | 2021.11.18 |
Java-자료구조 (Stack) (0) | 2021.11.17 |
Java-자료구조 (Queue) (0) | 2021.11.17 |
Java-자료구조(Array) (0) | 2021.11.16 |