기본적으로 자료구조에서 말하는 배열과 자바스크립트의 배열은 조금 다릅니다. 일단 우리는 JS 신을 믿기 때문에 JS 기반으로 설명하겠습니다.
JavaScript에서 배열의 특징은 다음과 같습니다.
배열은 요소 모음을 저장하는 데 사용되는 데이터 구조입니다.
배열의 요소는 숫자, 문자열 및 객체를 포함한 모든 데이터 유형일 수 있습니다.
배열의 각 요소는 0부터 시작하는 인덱스로 식별됩니다.
배열은 변경 가능합니다. 즉, 배열에서 요소를 추가하거나 제거할 수 있습니다.
배열의 길이는 요소를 추가하거나 제거할 때 동적으로 변경될 수 있습니다.
인덱스를 사용하여 배열 요소에 액세스할 수 있으며 for 루프를 사용하여 배열 요소를 반복할 수 있습니다.
JavaScript의 배열은 다차원적일 수 있습니다. 즉, 배열 안에 배열이 있을 수 있습니다.
JavaScript 배열에는 배열 요소에 대해 다양한 작업을 수행할 수 있는 내장 메서드가 있습니다.
JavaScript의 배열은 참조 유형입니다. 즉, 배열을 변수에 할당할 때 실제로는 배열의 복사본이 아니라 배열에 대한 참조를 할당하는 것입니다.
배열은 스택, 대기열 및 트리와 같은 데이터 구조를 나타내는 데 사용할 수 있으며 컴퓨터 과학 및 프로그래밍의 기본 데이터 구조입니다.
단일 연결 목록에서 각 노드는 시퀀스의 다음 노드에 대한 참조를 갖지만 이전 노드에 대한 참조는 갖지 않습니다. 즉, 목록 순회는 머리(첫 번째 요소)에서 꼬리(마지막 요소)까지 한 방향으로만 수행될 수 있습니다. 단일 연결 목록에서 요소를 삽입하고 삭제하려면 인접한 노드의 링크를 수정해야 합니다.
장점:
단점:
class Node {
constructor(data, next = null) {
this.data = data;
this.next = next;
}
}
class SinglyLinkedList {
constructor() {
this.head = null;
this.tail = null;
this.length = 0;
}
append(data) {
const node = new Node(data);
if (!this.head) {
this.head = node;
this.tail = node;
} else {
this.tail.next = node;
this.tail = node;
}
this.length++;
}
delete(data) {
if (!this.head) {
return;
}
if (this.head.data === data) {
this.head = this.head.next;
this.length--;
return;
}
let current = this.head;
while (current.next) {
if (current.next.data === data) {
current.next = current.next.next;
if (current.next === null) {
this.tail = current;
}
this.length--;
break;
}
current = current.next;
}
}
}
이중 연결 목록에서 각 노드는 시퀀스의 다음 노드와 이전 노드 모두에 대한 참조를 갖습니다. 이렇게 하면 양방향으로 목록을 순회할 수 있으므로 특정 작업에 유용할 수 있습니다. 이중 연결 목록에서 요소를 삽입하고 삭제하려면 인접한 노드의 링크도 수정해야 하지만 이 경우 한 개가 아닌 두 개의 링크 집합을 업데이트해야 합니다.
장점:
단점:
class Node {
constructor(data, prev = null, next = null) {
this.data = data;
this.prev = prev;
this.next = next;
}
}
class DoublyLinkedList {
constructor() {
this.head = null;
this.tail = null;
this.length = 0;
}
append(data) {
const node = new Node(data, this.tail);
if (!this.head) {
this.head = node;
this.tail = node;
} else {
this.tail.next = node;
this.tail = node;
}
this.length++;
}
delete(data) {
if (!this.head) {
return;
}
let current = this.head;
while (current) {
if (current.data === data) {
if (current === this.head) {
this.head = current.next;
if (this.head) {
this.head.prev = null;
}
} else if (current === this.tail) {
this.tail = current.prev;
if (this.tail) {
this.tail.next = null;
}
} else {
current.prev.next = current.next;
current.next.prev = current.prev;
}
this.length--;
break;
}
current = current.next;
}
}
}
list:
array(자료구조 관점):
전반적으로 연결된 목록은 빈번한 삽입 또는 삭제가 필요한 상황에 더 적합한 반면 배열은 임의 액세스 및 계산이 중요한 상황에 더 적합합니다. 연결 목록과 배열 사이의 선택은 응용 프로그램의 특정 요구 사항에 따라 다릅니다.
- 배열 혹은 스택의 기능이 필요할 때 사용할 수 있다.
- 내부적으로 포인터를 사용하기 때문에, 연결 리스트의 장점도 가지고 있다.
- 그러나 큐의 기능이 필요할 때는 직접 구현해야한다.
스택 데이터 구조는 푸시 및 팝의 두 가지 주요 작업을 지원하는 요소 모음입니다. 푸시 작업은 스택 맨 위에 요소를 추가하고 팝 작업은 스택에서 맨 위 요소를 제거합니다.
class Stack {
constructor() {
this.items = [];
}
push(element) {
this.items.push(element);
}
pop() {
if (this.isEmpty()) {
return "Underflow";
}
return this.items.pop();
}
peek() {
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length == 0;
}
printStack() {
let str = "";
for (let i = 0; i < this.items.length; i++) {
str += this.items[i] + " ";
}
return str;
}
}
아래는 위의 코드를 사용했을 때의 예시 코드 입니다 .
let stack = new Stack();
stack.push(10);
stack.push(20);
stack.push(30);
console.log(stack.printStack()); // Output: 10 20 30
console.log(stack.peek()); // Output: 30
stack.pop();
console.log(stack.printStack()); // Output: 10 20
큐 데이터 구조는 요소 모음을 저장하는 또 다른 기본 데이터 구조입니다. 스택과 비슷하지만 동작이 다릅니다. 대기열은 대기열에 넣기와 대기열에서 빼기라는 두 가지 주요 작업을 지원합니다. enqueue 작업은 요소를 대기열 끝에 추가하는 반면 dequeue 작업은 요소를 제거하고 대기열 맨 앞에 반환합니다.
class Queue {
constructor() {
this.items = [];
}
enqueue(element) {
this.items.push(element);
}
dequeue() {
if (this.isEmpty()) {
return "Underflow";
}
return this.items.shift();
}
front() {
if (this.isEmpty()) {
return "No elements in Queue";
}
return this.items[0];
}
isEmpty() {
return this.items.length == 0;
}
printQueue() {
let str = "";
for (let i = 0; i < this.items.length; i++) {
str += this.items[i] + " ";
}
return str;
}
}
아래는 큐 자료구조를 사용하는 예시 코드입니다.
let queue = new Queue();
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
console.log(queue.printQueue()); // Output: 10 20 30
console.log(queue.front()); // Output: 10
queue.dequeue();
console.log(queue.printQueue()); // Output: 20 30
트리 데이터 구조는 엣지(edge)로 연결된 노드로 구성된 널리 사용되는 계층적 데이터 구조입니다. 트리의 각 노드는 상위 노드가 없는 루트 노드를 제외하고 0개 이상의 하위 노드를 가질 수 있습니다.
class TreeNode {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BinaryTree {
constructor() {
this.root = null;
}
insert(value) {
const newNode = new TreeNode(value);
if (this.root === null) {
this.root = newNode;
} else {
this._insertNode(this.root, newNode);
}
}
_insertNode(node, newNode) {
if (newNode.value < node.value) {
if (node.left === null) {
node.left = newNode;
} else {
this._insertNode(node.left, newNode);
}
} else {
if (node.right === null) {
node.right = newNode;
} else {
this._insertNode(node.right, newNode);
}
}
}
search(value) {
return this._searchNode(this.root, value);
}
_searchNode(node, value) {
if (node === null) {
return null;
} else if (value < node.value) {
return this._searchNode(node.left, value);
} else if (value > node.value) {
return this._searchNode(node.right, value);
} else {
return node;
}
}
traverseInOrder() {
const result = [];
this._traverseInOrder(this.root, result);
return result;
}
_traverseInOrder(node, result) {
if (node !== null) {
this._traverseInOrder(node.left, result);
result.push(node.value);
this._traverseInOrder(node.right, result);
}
}
}
// Example usage
const tree = new BinaryTree();
tree.insert(5);
tree.insert(3);
tree.insert(7);
tree.insert(1);
tree.insert(4);
tree.insert(6);
tree.insert(8);
console.log(tree.traverseInOrder()); // [1, 3, 4, 5, 6, 7, 8]
console.log(tree.search(4)); // TreeNode { value: 4, left: TreeNode {...}, right: TreeNode {...} }
우선순위 큐는 각 요소가 우선순위 값과 연관되는 특별한 유형의 큐입니다. 우선순위 대기열에 있는 요소의 우선순위에 따라 처리되는 순서가 결정됩니다. 우선 순위 값이 높은 요소는 우선 순위 값이 낮은 요소보다 먼저 처리됩니다
즉, 우선순위 대기열은 일반 대기열과 유사하지만 대기열의 각 항목에는 우선순위가 연결되어 있다는 점만 다릅니다. 항목이 우선순위 대기열에 추가되면 항목이 추가된 순서가 아니라 우선순위에 따라 대기열에 배치됩니다.
우선 순위 큐는 힙, 이진 검색 트리 및 배열을 비롯한 다양한 데이터 구조를 사용하여 구현할 수 있습니다. 가장 일반적인 구현은 힙 데이터 구조를 사용합니다.
우선 순위 대기열은 일반적으로 운영 체제, 네트워크 라우팅 알고리즘 및 시뮬레이션 시스템과 같은 컴퓨터 과학 응용 프로그램에서 사용됩니다.
직접 짜는 것...그것은 거의 무리...
class MaxHeap {
constructor() {
this.heap = [];
}
getLeftChildIndex(parentIndex) {
return (2 * parentIndex) + 1;
}
getRightChildIndex(parentIndex) {
return (2 * parentIndex) + 2;
}
getParentIndex(childIndex) {
return Math.floor((childIndex - 1) / 2);
}
hasLeftChild(index) {
return this.getLeftChildIndex(index) < this.heap.length;
}
hasRightChild(index) {
return this.getRightChildIndex(index) < this.heap.length;
}
hasParent(index) {
return this.getParentIndex(index) >= 0;
}
leftChild(index) {
return this.heap[this.getLeftChildIndex(index)];
}
rightChild(index) {
return this.heap[this.getRightChildIndex(index)];
}
parent(index) {
return this.heap[this.getParentIndex(index)];
}
swap(indexOne, indexTwo) {
const temp = this.heap[indexOne];
this.heap[indexOne] = this.heap[indexTwo];
this.heap[indexTwo] = temp;
}
peek() {
if (this.heap.length === 0) {
return null;
}
return this.heap[0];
}
insert(value) {
this.heap.push(value);
this.heapifyUp();
}
heapifyUp() {
let index = this.heap.length - 1;
while (this.hasParent(index) && this.parent(index) < this.heap[index]) {
const parentIndex = this.getParentIndex(index);
this.swap(index, parentIndex);
index = parentIndex;
}
}
poll() {
if (this.heap.length === 0) {
return null;
}
const item = this.heap[0];
this.heap[0] = this.heap.pop();
this.heapifyDown();
return item;
}
heapifyDown() {
let index = 0;
while (this.hasLeftChild(index)) {
let largerChildIndex = this.getLeftChildIndex(index);
if (this.hasRightChild(index) && this.rightChild(index) > this.leftChild(index)) {
largerChildIndex = this.getRightChildIndex(index);
}
if (this.heap[index] > this.heap[largerChildIndex]) {
break;
} else {
this.swap(index, largerChildIndex);
}
index = largerChildIndex;
}
}
}
그래프는 vertices 집합과 이를 연결하는 edges 집합으로 구성된 데이터 구조입니다. vertices 간의 관계는 인접 행렬 또는 인접 목록을 사용하여 나타낼 수 있습니다. 인접 행렬은 두 vertices 사이에 edges가 있는지 여부를 저장하는 2차원 배열이며, 인접 목록은 각 vertices의 이웃을 저장하는 연결 목록 모음입니다.
vertice: 정점(또는 노드)은 그래프의 기본 단위입니다. 일반적으로 그래프 다이어그램에서 점이나 원으로 표시됩니다.
edge: 에지는 두 정점을 연결하는 선으로 이들 간의 관계를 나타냅니다. 에지에는 관련 가중치 또는 비용이 있을 수 있습니다.
인접행렬(Adjacency Matrix): 인접행렬은 그래프에서 두 정점 사이에 간선이 있는지 여부를 저장하는 2차원 배열이다.
인접 리스트: 인접 리스트는 그래프에서 각 정점의 이웃을 저장하는 연결 리스트의 모음입니다.
정점에 해당하는 행과 열이 있는 행렬과 정점 사이의 가장자리를 나타내는 셀로 나타낼 수 있습니다. 값이 1인 셀은 가장자리가 있음을 나타내고 값이 0인 셀은 가장자리가 없음을 나타냅니다. 유향 그래프의 경우 행렬이 대칭이 아닐 수 있습니다.
추가로. 무방향 무가중치 그래프가 있습니다.
연결되어 있는 상태만 나타내는 방식입니다.
아래는 방향 + 가중치 그래프 입니다. 나머지는 응용해서 생각해보세요
각 꼭짓점에는 목록에 인덱싱하여 액세스할 수 있는 이웃 목록이 연결되어 있습니다. 연결된 목록의 각 항목은 정점을 이웃에 연결하는 가장자리를 나타내며 가장자리의 가중치와 같은 정보를 포함할 수 있습니다.