📗 Docs
연결 리스트(Linked List)
파일과 미디어
date
Apr 16, 2023
slug
Algorithm-LinkedList
author
status
Public
tags
Algorithm
Java
summary
LinkedLisit 기본 개념 정리
type
Post
thumbnail
category
📗 Docs
updatedAt
Apr 17, 2023 06:45 AM
연결 리스트(Linked List)
- 데이터를 링크로 연결해서 관리하는 자료구조
- 자료의 순서는 정해져 있지만, 메모리상 연속성이 보장되지는 않음 ↔ 배열(Array)는 이와 다르게 메모리상에서의 연속성이 보장됨
연결 리스트의 장점
- 데이터 공간을 미리 할당할 필요 없음.
- 즉, 리스트의 길이가 가변적이라 데이처 추가/삭제 용이
연결 리스트의 단점
- 연결구조를 위한 별도 데이터 공간 필요
- 연결 정보를 찾는 시간이 필요
- 데이터 추가, 삭제 시 앞뒤 데이터의 연결을 재구성하는 작업 필요
연결 리스트 기본 구조
- 노드 (Node)
- 데이터 저장 단위로, 값과 포인터로 구성
- 포인터(Pointer) : 다음 노드나 이전 노드의 연결 정보

연결 리스트 기본 연산
- 데이터 추가
- 데이터 추가 위치(head, 중간, tail)에 따른 연결 작업 필요

- 추가할 데이터를 담은 노드 생성
- 링크 연결 작업
- head 이전 작업

- 추가할 데이터를 담을 노드 생성
- head로부터 끝 노드까지 순회
- 링크 연결 작업

- 추가할 데이터를 담을 노드 생성
- head로부터 데이터 추가 위치 직전 노드까지 순회
- 링크 연결 작업
- 데이터 삭제
- 데이터 추가와 반대의 작업 수행
연결 리스트 구성 코드
class Node {
int data;
Node next; // pointer
public Node() {}
public Node(int data, Node next) {
this.data - data;
this.next= next;
}
}
class LinkedList {
Node head;
public LinkedList(Node head){
this.head = head;
}
// 연결 리스트 비어있는지 확인
public boolean isEmpty(){
if(this.head == null){
return true;
}
return false;
}
//연결 리스트의 맨 뒤에 데이터 추가
public void addData(int data){
if(this.head == null){
this.head = new Node(data, null);
} else {
Node cur = this.head;
while(cur.next != null){
cur = cur.next;
}
cur.next = new Node(data, null);
}
}
// 데이터 삭
public void removeData(){
if(this.isEmpty)){
System.out.println("List is empty");
return;
}
Node cur = this.head;
Node prev = cur;
while(cur.next != null){
prev = cur;
cur = cur.next;
}
if(cur == this.head){
this.head = null; // 뒤에 따라오는 LinkedList가 없으면
} else {
prev.next = null;
}
}
// 연결 리스트에서 데이터 찾기
public void findData(int data){
if(this.isEmpty()){
System.out.println("List is empty");
return;
}
Node cur = this.head;
while (cur != null) {
if (cur.data == data) {
System.out.println("Data exist!");
return;
}
cur = cur.next;
}
System.out.println("Data not found!");
}
// 연결 리스트의 모든 데이터 출력
public void showData(){
if(this.isEmpty()){
System.out.println("List is empty");
return;
}
Node cur = this.head;
while (cur!=null){
System.out.print(cur.data + " ");
cur= cur.next;
}
System.out.println();
}
}
단순 연결 리스트 구현 완성(노드 앞,중간,뒤 추가)
class LinkedList2 extends LinkedList {
public LinkedList2(Node node) {
this.head = node;
}
// 연결 리스트에 데이터 추가
// before_data 가 null인 경우, 가장 뒤에 추가
// before_data 에 값이 있는 경우, 해당 값을 가진 노드 앞에 추가
public void addData(int data, Integer beforeData) {
if (this.head == null) {
this.head = new Node(data, null);
} else if (beforeData == null) { // 뒤에 데이터를 추가하는 경우
Node cur = this.head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = new Node(data, null);
} else {
Node cur = this.head;
Node pre = cur;
while (cur != null) {
if (cur.data == beforeData) {
if(cur == this.head){
this.head = new Node(data, this.head); // 맨앞 노드 추가 후 헤드 옮김
} else {
pre.next = new Node(data, cur);
}
break;
}
pre = cur;
cur = cur.next;
}
}
}
public void removeData(int data) {
if (this.isEmpty()) {
System.out.println("List is empty");
return;
}
Node cur = this.head;
Node pre = cur;
while (cur != null) {
if (cur.data == data) {
if (cur == this.head) {
this.head = cur.next;
} else {
pre.next = cur.next;
}
break;
}
pre = cur;
cur = cur.next;
}
}
}
양방향 연결 리스트(Doubly Linked List)
// Practice2
// 양방향 연결 리스트 (Doubly Linked List) 구현
class NodeBi {
int data;
NodeBi next;
NodeBi prev;
public NodeBi(int data, NodeBi next, NodeBi prev) {
this.data = data;
this.next = next;
this.prev = prev;
}
}
class DoublyLinkedList extends LinkedList {
NodeBi head;
NodeBi tail;
DoublyLinkedList(NodeBi node) {
this.head = node;
this.tail = node;
}
public boolean isEmpty() {
if (this.head == null) {
return true;
}
return false;
}
public void addData(int data, Integer beforeData) {
if (this.head == null) {
this.head = new NodeBi(data, null, null);
this.tail = this.head;
} else if (beforeData == null) {
this.tail.next = new NodeBi(data, null, this.tail);
this.tail = this.tail.next;
} else {
NodeBi cur = this.head;
NodeBi pre = cur;
while (cur != null) {
if (cur.data == beforeData) {
if (cur == this.head) { // 헤드일 경우
this.head = new NodeBi(data, this.head, null);
this.head.next.prev = this.head;
} else { //헤드가 아닐 경우 == 중간에 데이터를 넣는 경우
pre.next = new NodeBi(data, cur, pre);
cur.prev = pre.next;
}
break;
}
pre = cur;
cur = cur.next;
}
}
}
public void removeData(int data) {
if (this.isEmpty()) {
System.out.println("List is empty");
return;
}
NodeBi cur = this.head;
NodeBi pre = cur;
while (cur != null) {
if (cur.data == data) {
if (cur == this.head && cur == this.tail) { //노드가 하나인 상태
this.head = null;
this.tail = null;
} else if (cur == this.head) {
this.head = cur.next;
this.head.prev = null; // 기존에 컬 head 제거
} else if (cur == this.tail) {
this.tail = this.tail.prev; //기존 테일이 한 칸 앞으로 이동
this.tail.next = null;
} else { //중간 노드 삭제
pre.next = cur.next;
cur.next.prev = pre;
}
break;
}
pre = cur;
cur = cur.next;
}
}
public void showData() {
if (this.isEmpty()) {
System.out.println("list is empty!");
return;
}
NodeBi cur = this.head; // head에서부터 tail까지 쭉 출력
while(cur != null){
System.out.print(cur.data + " ");
cur = cur.next;
}
System.out.println();
}
public void showDataFromTail(){
if(this.isEmpty()){
System.out.println("List is empty!");
return;
}
NodeBi cur = this.tail;
while(cur != null){
System.out.print(cur.data + " ");
cur = cur.prev;
}
System.out.println();
}
}