- 링크드 리스트 구조
- 연결 리스트
- 떨어진 곳에 존재하는 데이터를 화살표로 연결해서 관리하는 데이터 구조
- 배열의 미리 공간을 지정해야 하는 단점을 극복한 자료구조
- 링크드 리스트 기본 구조와 용어
- 노드(Node): 데이터 저장 단위(데이터값, 포인터)로 구성
- 포인터(Pointer): 각 노드 안에서, 다음이나 이전의 노드와의 연결 정보를 가지고 있는 공간
- Linked List 장단점
- 장점
- 단점
- 연결을 위한 별도 데이터 공간이 필요하므로 저장공간 효율이 높지 않음
- 연결 정보를 찾는 시간이 필요하므로 접근 속도가 느림
- 중간 데이터 삭제 시, 앞뒤 데이터의 연결을 재구성해야 하는 부가적인 작업 필요
- 자바스크립트로 Linked List 구현
const LinkedList = (function() {
function LinkedList() {
this.head = null;
}
function Node(data, next=null) {
this.data = data;
this.next = next;
}
return LinkedList;
})();
const LinkedList = (function() {
function LinkedList() {
this.head = null;
}
function Node(data, next=null) {
this.data = data;
this.next = next;
}
// 노드 추가
LinkedList.prototype.add = function(data) {
let node = new Node(data);
let curNode = this.head;
// 노드가 없을 경우, 해당 노드를 head에 추가
if( !curNode ) {
this.head = node;
} else {
// 마지막 노드 추적
while(curNode.next) {
curNode = curNode.next;
}
// 마지막 노드의 next에 해당 노드 추가
curNode.next = node;
}
}
return LinkedList;
})();
const LinkedList = (function() {
function LinkedList() {
this.head = null;
}
function Node(data, next=null) {
this.data = data;
this.next = next;
}
/**
* 노드 삭제
* 1. head 삭제
* 2. 마지막 노드 삭제
* 3. 중간 노드 삭제
*/
LinkedList.prototype.remove = function(data) {
let curNode = this.head;
if( !curNode ) return;
// head를 삭제하는 경우
if( curNode.data === data ) {
this.head = this.head.next; // 두번째 노드를 head로 변경
// 그 외의 노드를 삭제하는 경우
} else {
while(curNode.next) {
// 다음 노드가 삭제할 노드일 경우
if( curNode.next.data === data ) {
curNode.next = curNode.next.next || null; // 삭제할 노드의 다음노드를 연결
break;
}
curNode = curNode.next;
}
}
}
return LinkedList;
})();
const LinkedList = (function() {
function LinkedList() {
this.head = null;
}
function Node(data, next=null) {
this.data = data;
this.next = next;
}
// 노드 추가
LinkedList.prototype.add = function(data) {
let node = new Node(data);
let curNode = this.head;
// 노드가 없을 경우, 해당 노드를 head에 추가
if( !curNode ) {
this.head = node;
} else {
// 마지막 노드 추적
while(curNode.next) {
curNode = curNode.next;
}
// 마지막 노드의 next에 해당 노드 추가
curNode.next = node;
}
}
/**
* 노드 삭제
* 1. head 삭제
* 2. 마지막 노드 삭제
* 3. 중간 노드 삭제
*/
LinkedList.prototype.remove = function(data) {
let curNode = this.head;
if( !curNode ) return;
// head를 삭제하는 경우
if( curNode.data === data ) {
this.head = this.head.next; // 두번째 노드를 head로 변경
// 그 외의 노드를 삭제하는 경우
} else {
while(curNode.next) {
// 다음 노드가 삭제할 노드일 경우
if( curNode.next.data === data ) {
curNode.next = curNode.next.next || null; // 삭제할 노드의 다음노드를 연결
break;
}
curNode = curNode.next;
}
}
}
// 노드 검색
LinkedList.prototype.search = function(data) {
let curNode = this.head;
while(curNode) {
if( curNode.data === data ) {
return curNode;
}
curNode = curNode.next;
}
return false;
}
LinkedList.prototype.print = function() {
let node = this.head;
while(node) {
console.log(node.data);
node = node.next;
}
}
return LinkedList;
})();
const linkedList = new LinkedList();
linkedList.add(1); // 1추가
linkedList.add(2); // 2추가
linkedList.add(3); // 3추가
linkedList.add(4); // 4추가
linkedList.add(5); // 5추가
linkedList.remove(3); // 3제거
linkedList.remove(1); // 1제거(head)
linkedList.print(); // 2, 4, 5 출력
- 더블 링크드 리스트(Double Linked List)
- 이중 연결 리스트
- 양방향으로 연결되어 있어서 노드 탐색이 양쪽으로 가능
- Linked List, Node 구현
- Linked List에 tail property 추가
- Node에 prev property 추가
const LinkedList = (function() {
function LinkedList() {
this.head = null;
this.tail = null;
}
function Node(data, prev=null, next=null) {
this.data = data;
this.prev = prev;
this.next = next;
}
return LinkedList;
})();
const LinkedList = (function() {
function LinkedList() {
this.head = null;
this.tail = null;
}
function Node(data, prev=null, next=null) {
this.data = data;
this.prev = prev;
this.next = next;
}
LinkedList.prototype.add = function(data) {
let node = new Node(data);
let curNode = this.head;
this.tail = node; // tail에 해당 노드 추가
if( !curNode ) {
this.head = node;
} else {
while(curNode.next) {
curNode = curNode.next;
}
curNode.next = node;
node.prev = curNode; // 해당 노드의 이전에 현재 노드 매핑
}
}
return LinkedList;
})();
const LinkedList = (function() {
function LinkedList() {
this.head = null;
this.tail = null;
}
function Node(data, prev=null, next=null) {
this.data = data;
this.prev = prev;
this.next = next;
}
LinkedList.prototype.insert_before = function(data, before_data) {
let node = new Node(data);
if( !this.head ) {
this.head = node;
this.tail = node;
return true;
} else {
let curNode = this.tail;
while(curNode.data !== before_data) {
curNode = curNode.prev;
// before_data가 없는 경우 false return
if( !curNode ) return false;
}
// before_data의 바로 앞의 노드
let beforeNode = curNode.prev;
beforeNode.next = node; // 앞의 노드의 next를 추가할 노드로 변경
curNode.prev = node; // 현재 노드의 prev를 추가할 노드로 변경
node.prev = beforeNode; // 추가할 노드의 prev는 before_data의 앞 노드
node.next = curNode; // 추가할 노드의 next는 현재 노드
return true;
}
}
LinkedList.prototype.insert_after = function(data, after_data) {
let node = new Node(data);
if( !this.head ) {
this.head = node;
this.tail = node;
return true;
} else {
let curNode = this.head;
while(curNode.data !== after_data) {
curNode = curNode.next;
// after_data가 없는 경우 false return
if( !curNode ) return false;
}
// after_data의 바로 뒤의 노드
let afterNode = curNode.next;
afterNode.prev = node; // after_data 뒤의 노드의 prev를 추가할 노드로 변경
curNode.next = node; // 현재 노드의 next를 추가할 노드로 변경
node.prev = curNode; // 추가할 노드의 prev는 현재 노드
node.next = afterNode; // 추가할 노드의 next는 after_data의 뒤의 노드
return true;
}
}
return LinkedList;
})();
const LinkedList = (function() {
function LinkedList() {
this.head = null;
this.tail = null;
}
function Node(data, prev=null, next=null) {
this.data = data;
this.prev = prev;
this.next = next;
}
LinkedList.prototype.search_from_head = function(data) {
let curNode = this.head;
while(curNode) {
if( curNode.data === data ) {
return curNode;
}
curNode = curNode.next;
}
return false;
}
LinkedList.prototype.search_from_tail = function(data) {
let curNode = this.tail;
while(curNode) {
if( curNode.data === data ) {
return curNode;
}
curNode = curNode.prev;
}
return false;
}
return LinkedList;
})();
const LinkedList = (function() {
function LinkedList() {
this.head = null;
this.tail = null;
}
function Node(data, prev=null, next=null) {
this.data = data;
this.prev = prev;
this.next = next;
}
LinkedList.prototype.add = function(data) {
let node = new Node(data);
let curNode = this.head;
this.tail = node;
if( !curNode ) {
this.head = node;
} else {
while(curNode.next) {
curNode = curNode.next;
}
curNode.next = node;
node.prev = curNode;
}
}
LinkedList.prototype.search_from_head = function(data) {
let curNode = this.head;
while(curNode) {
if( curNode.data === data ) {
return curNode;
}
curNode = curNode.next;
}
return false;
}
LinkedList.prototype.search_from_tail = function(data) {
let curNode = this.tail;
while(curNode) {
if( curNode.data === data ) {
return curNode;
}
curNode = curNode.prev;
}
return false;
}
LinkedList.prototype.insert_before = function(data, before_data) {
let node = new Node(data);
if( !this.head ) {
this.head = node;
this.tail = node;
return true;
} else {
let curNode = this.tail;
while(curNode.data !== before_data) {
curNode = curNode.prev;
// before_data가 없는 경우 false return
if( !curNode ) return false;
}
// before_data의 바로 앞의 노드
let beforeNode = curNode.prev;
beforeNode.next = node; // 앞의 노드의 next를 추가할 노드로 변경
curNode.prev = node; // 현재 노드의 prev를 추가할 노드로 변경
node.prev = beforeNode; // 추가할 노드의 prev는 before_data의 앞 노드
node.next = curNode; // 추가할 노드의 next는 현재 노드
return true;
}
}
LinkedList.prototype.insert_after = function(data, after_data) {
let node = new Node(data);
if( !this.head ) {
this.head = node;
this.tail = node;
return true;
} else {
let curNode = this.head;
while(curNode.data !== after_data) {
curNode = curNode.next;
// after_data가 없는 경우 false return
if( !curNode ) return false;
}
// after_data의 바로 뒤의 노드
let afterNode = curNode.next;
afterNode.prev = node; // after_data 뒤의 노드의 prev를 추가할 노드로 변경
curNode.next = node; // 현재 노드의 next를 추가할 노드로 변경
node.prev = curNode; // 추가할 노드의 prev는 현재 노드
node.next = afterNode; // 추가할 노드의 next는 after_data의 뒤의 노드
return true;
}
}
LinkedList.prototype.print = function() {
let node = this.head;
while(node) {
console.log(node.data);
node = node.next;
}
}
return LinkedList;
})();
const linkedList = new LinkedList();
linkedList.add(1); // 1추가
linkedList.add(2); // 2추가
linkedList.add(3); // 3추가
linkedList.add(4); // 4추가
linkedList.add(5); // 5추가
linkedList.insert_before(3.5,4); // 4앞에 3.5추가
linkedList.insert_after(2.5,2); // 2뒤에 2.5추가
linkedList.print(); // 1, 2, 2.5, 3, 3.5, 4, 5 출력