1. 이중 연결 리스트의 구조(Doubly Linked List) 기본 구조
- 이중 연결 리스트의 장단점
- 장점
- 양방향으로 연결되어 있어서 노드 탐색이 양쪽으로 가능하다.
- 단점
- 그만큼 이전 노드의 주소를 담을 공간이 하나 더 필요하다.
- 장점
2. Java로 이중 연결 리스트 구현하기
- Node 클래스 구현하기 연결 리스트에 비해 prev 필드가 하나 더 늘었다.
public class Node<T> {
T data;
Node<T> next;
Node<T> prev;
public Node(T data){
this.data = data;
}
}
- Node 추가하기
public void addNode(T data) {
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;
}
node.next = new Node<T>(data);
node.next.prev = node;
this.tail = node.next;
}
}
- Node data 전체 출력
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);
}
}
}
- 헤드 부터 시작하여 특정 데이터 찾기
public 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.data;
} else {
node = node.next;
}
}
return null;
}
}
- 꼬리 부터 시작하여 특정 데이터 찾기
public 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.data;
} else {
node = node.prev;
}
}
return null;
}
}
- 특정 데이터 삭제하기
public boolean delNode (T isData) {
if(this.head == null){
return false;
} else {
Node<T> node = this.head;
if (node.data == isData){
this.head = this.head.next;
this.head.prev = null;
return true;
} else {
while(node.next != null) {
if(node.next.data == isData){
Node<T> nodeTemp = node;
Node<T> nodeDel = nodeTemp.next;
nodeTemp.next = nodeTemp.next.next;
if (nodeTemp.next != null){
nodeTemp.next.prev = nodeTemp;
}
if (nodeDel == this.tail) {
this.tail = nodeTemp;
}
return true;
} else {
node = node.next;
}
}
return false;
}
}
}
- 전체 코드
public class DoubleLinkedList<T> {
public Node<T> head = null;
public Node<T> tail = null;
public class Node<T>{
T data;
Node<T> prev = null;
Node<T> next = null;
public Node(T data){
this.data = data;
}
}
public void addNode(T data) {
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; // 다음 노드를 가져온다.
}
node.next = new Node<T>(data); // 노드의 끝에서 노드를 생성한다.
node.next.prev = node; // 새로 만든 노드의 이전 노드를 설정
this.tail = node.next; // 제일 끝 노드를 새로 생성 했으므로 테일을 재설정.
}
}
public void printAll() {
if (this.head != null) { // 헤드가 널이 아니어야 출력이 가능하다.
System.out.println(this.head.data); // 헤드의 데이터 부터 출력
Node<T> node = this.head; // 임시 노드에 헤드 넣기
while(node.next != null) { // 다음 노드가 없을 때까지 반복
node = node.next; // 다음 노드 설정
System.out.println(node.data); // 노드 데이터 출력
}
}
}
public 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.data; // 노드의 데이터를 반환
} else { // 그게 아니면
node = node.next; // 다음 노드 체크
}
}
return null; // 반복을 모두 돌고도 찾는 데이터가 없으면 널 반환
}
}
public 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.data; // 그 노드의 데이터 반환
} else {
node = node.prev; // 이전 노드로
}
}
return null; // 반복을 전부 완료하고 없으면 널 반환
}
}
public boolean insertToFront ( T existedData, T addData) {
if (this.head == null) { // 헤드가 널이라면
this.head = new Node<T>(addData); // 헤드에 새로운 노드 생성
this.tail = this.head; // 노드가 하나이므로 테일로도 설정
return true; // 데이터 추가 성공이므로 true 반환
} else if ( this.head.data == existedData) { // 헤드의 데이터가 찾는 데이터일 때
Node<T> newHead = new Node<T>(addData); // 새로운 헤드에 새 노드를 만들어 대입
newHead.next = this.head; // 새 헤드의 다음 노드로 헤드 대입
this.head = newHead; // 헤드에 새 노드 대입
this.head.next.prev = this.head; // 다음 노드의 이전 노드로 헤드 대입
return true; // 데이터 추가 성공이므로 true 반환
} else { // 헤드가 존재하고 찾는 데이터가 헤드에 있지 않을 때
Node<T> node = this.head; // 노드에 헤드 대입
while ( node != null) { // 노드가 널이 아닐 때 반복
if ( node.data == existedData) { // 노드의 데이터가 찾는 데이터라면
Node<T> nodePrev = node.prev; // 노드의 이전 노드 가져옴
nodePrev.next = new Node<T>(addData); // 이전노드의 다음 노드로 새 노드 대입
nodePrev.next.next = node; // 이전 노드의 다음다음 즉 새 노드의 다음 노드 로 노드 대입
nodePrev.next.prev = nodePrev; // 새 노드의 이전 노드로 이전 노드 지정
node.prev = nodePrev.next; // 노드의 이전 노드로 새 노드 지정
return true; // 데이터 추가가 성공적이므로 true 반환
} else {
node = node.next; // 찾는 데이터가 아니라면 다음 노드 불러옴
}
}
return false; // 반복이 전부 종료 되더라도 못찾으면 false 반환
}
}
public boolean delNode(T isData) {
if ( this.head == null) { // 헤드가 널이면
return false; // 지울 수 있는게 없기에 false 반환
} else {
Node<T> node = this.head;
if (node.data == isData) { // 헤드의 데이터가 바로 지우려는 데이터일 때
this.head = this.head.next; // 헤드는 헤드의 다음으로 지정
this.head.prev = null; // 다음 헤드의 이전 노드는 널로 지정
return true; // 지움을 성공해서 true 반환
} else { // 헤드의 데이터가 지우려는 데이터가 아닐 때
while(node.next != null) { // 다음 노드가 널이 아니면 반복
if(node.next.data == isData) { // 다음 노드의 데이터가 지우려는 데이터일 때
Node<T> nodeTemp = node; // 임시 노드에 노드 저장
Node<T> nodeDel = nodeTemp.next; // 지우려는 노드는 다음 노드 이것도 저장
nodeTemp.next = nodeTemp.next.next; // 임시 노드의 다음노드를 다음다음 노드로 저장
if (nodeTemp.next != null) { // 임시노드의 다음노드가 있다면
nodeTemp.next.prev = nodeTemp; // 임시노드의 다음 노드의 이전노드를 임시노드로 저장
}
if (nodeDel == this.tail) { // 지우려는 노드가 테일 이었다면
this.tail = nodeTemp; // 테일 노드를 임시노드로 지정
}
return true;
} else { // 지우려는 노드의 데이터를 못찾았다면 다음 노드로 넘어감
node = node.next;
}
}
return false; // 반복을 다 돌고도 못찾았다면 false 반환.
}
}
}
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.delNode(1);
MyLinkedList.delNode(2);
MyLinkedList.delNode(3);
MyLinkedList.delNode(4);
MyLinkedList.delNode(5);
MyLinkedList.printAll();
System.out.println("----------------");
MyLinkedList.insertToFront(6, 2);
MyLinkedList.insertToFront(1, 0);
MyLinkedList.printAll();
System.out.println("----------------");
MyLinkedList.addNode(6);
MyLinkedList.printAll();
}
}
'자료구조와 알고리즘 (Java)' 카테고리의 다른 글
[자료구조][Java] 연결리스트/링크드 리스트(Linked List) (0) | 2022.04.19 |
---|---|
[자료구조][Java] 스택 (Stack) (0) | 2022.04.19 |
[자료구조][Java] 큐 (Queue) (0) | 2022.04.19 |
[자료구조][Java] 배열( Array ) (0) | 2022.04.19 |
자료구조, 알고리즘 왜 배워야 하나요? (0) | 2022.03.15 |
댓글