From 5022558cdce80fd0d2657f87cecfb5c4e7694090 Mon Sep 17 00:00:00 2001 From: JengYoung Date: Tue, 29 Nov 2022 23:21:56 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=E2=9C=A8=20=EC=96=91=EB=B0=A9=ED=96=A5=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=A5=BC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\354\236\254\354\230\201/index.js" | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 "JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/index.js" diff --git "a/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/index.js" "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/index.js" new file mode 100644 index 0000000..e4360b6 --- /dev/null +++ "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/index.js" @@ -0,0 +1,93 @@ +// [x] 양방향 연결리스트는 각 노드의 prev와 next로 이동할 수 있어야 합니다. +class Node { + constructor(val, prev = null, next = null) { + this.val = val; + this.prev = prev; + this.next = next; + } +} + +export class DoubleLinkedList { + constructor(val) { + this.node = val ? new Node(val) : null; + this.head = val ? this.node : null; + this.tail = val ? this.node : null; + + this.cnt = val ? 1 : 0; + } + + // [x] insert메서드를 통해 특정 인덱스의 노드에 삽입할 수 있어야 해요. + insert(val) { + if (val === null) throw new Error('값은 null이 될 수 없습니다.'); + + if (!this.cnt) { + const nowNode = new Node(val); + this.node = nowNode; + this.head = nowNode; + this.tail = nowNode; + + this.cnt += 1; + + return this; + } + + const nowNode = new Node(val, this.node, this.node.next ?? this.head); + this.node.next = nowNode; + this.node = nowNode; + + if (this.node.next === this.head) this.tail = nowNode; + + this.cnt += 1; + return this; + } + + // [x] get를 통해 원하는 인덱스의 노드를 가져올 수 있어야 해요. + getNthNode(order) { + let i = 0; + let now = this.head; + while (i < order) { + now = now.next; + } + + return now; + } + + get nowNode() { + return this.node; + } + + // [x] update를 통해 해당 인덱스의 노드를 수정할 수 있어야 해요. + update(val) { + this.node.val = val; + + return this; + } + + // [x] remove를 통해 해당 인덱스의 노드를 삭제할 수 있어야 해요. + remove() { + if (!this.cnt) return this; + + if (this.cnt === 1) { + this.node = null; + this.head = null; + this.tail = null; + + this.cnt -= 1; + return this; + } + + this.node.next.prev = this.node.prev; + this.node.prev.next = this.node.next; + + this.node = this.node.next; + + this.cnt -= 1; + return this; + } + + get length() { + return this.cnt; + } +} + +const doubleLinkedList = new DoubleLinkedList(); From f59b5042ce5df09fcb73a01a593d8fea2a254362 Mon Sep 17 00:00:00 2001 From: JengYoung Date: Tue, 29 Nov 2022 23:56:04 +0900 Subject: [PATCH 2/4] =?UTF-8?q?:white=5Fcheck=5Fmark:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\354\236\254\354\230\201/README.md" | 31 ++++++++ .../\354\236\254\354\230\201/index.js" | 74 +++++++++++++----- .../\354\236\254\354\230\201/package.json" | 7 ++ .../\354\236\254\354\230\201/test.js" | 75 +++++++++++++++++++ 4 files changed, 167 insertions(+), 20 deletions(-) create mode 100644 "JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/README.md" create mode 100644 "JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/package.json" create mode 100644 "JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/test.js" diff --git "a/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/README.md" "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/README.md" new file mode 100644 index 0000000..882fc4c --- /dev/null +++ "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/README.md" @@ -0,0 +1,31 @@ +## HOW TO CHECK + +루트 디렉토리를 기준으로 다음을 순차적으로 입력해주세요. + +### 현재 과제 디렉토리로 이동 + +```bash +cd JavaScript +cd 07주차 +cd assignment +cd 재영 +``` + +### 커맨드 실행 + +```bash +npm test +``` + +`pnpm`을 쓰신다면 `pnpm`으로 테스트 가능합니다. +```bash +pnpm test +``` + +`yarn`을 쓰신다면 `yarn`으로 테스트 가능합니다. +```bash +yarn test +``` + +### 테스트 코드 작성 + diff --git "a/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/index.js" "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/index.js" index e4360b6..3630fe9 100644 --- "a/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/index.js" +++ "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/index.js" @@ -16,36 +16,52 @@ export class DoubleLinkedList { this.cnt = val ? 1 : 0; } + get prevNode() { + return this.node.prev ?? this.node; + } + + get nextNode() { + return this.node.next ?? this.node; + } + // [x] insert메서드를 통해 특정 인덱스의 노드에 삽입할 수 있어야 해요. insert(val) { - if (val === null) throw new Error('값은 null이 될 수 없습니다.'); - if (!this.cnt) { const nowNode = new Node(val); this.node = nowNode; this.head = nowNode; this.tail = nowNode; - - this.cnt += 1; - - return this; + } else { + const nowNode = new Node(val, this.node, this.node.next ?? this.head); + this.nextNode.prev = nowNode; + this.node.next = nowNode; + this.node = nowNode; + + if (this.node.next === this.head) this.tail = nowNode; } - const nowNode = new Node(val, this.node, this.node.next ?? this.head); - this.node.next = nowNode; - this.node = nowNode; - - if (this.node.next === this.head) this.tail = nowNode; - this.cnt += 1; + return this; } // [x] get를 통해 원하는 인덱스의 노드를 가져올 수 있어야 해요. - getNthNode(order) { + getNthNodeFromHead(order) { let i = 0; let now = this.head; while (i < order) { + i += 1; + now = now.next; + } + + return now; + } + + getNthNode(order) { + let i = 0; + let now = this.node; + while (i < order) { + i += 1; now = now.next; } @@ -69,19 +85,37 @@ export class DoubleLinkedList { if (this.cnt === 1) { this.node = null; + this.head = null; this.tail = null; - - this.cnt -= 1; - return this; + } else { + this.nextNode.prev = this.node.prev; + this.prevNode.next = this.node.next; + + if (this.head === this.node) this.head = this.node.next; + this.node = this.node.next; } - this.node.next.prev = this.node.prev; - this.node.prev.next = this.node.next; + this.cnt -= 1; - this.node = this.node.next; + return this; + } - this.cnt -= 1; + goPrev() { + if (this.cnt === 0) return this; + if (this.cnt === 1) return this.node; + + this.node = this.node.prev; + + return this; + } + + goNext() { + if (this.cnt === 0) return this; + if (this.cnt === 1) return this.node; + + this.node = this.node.next; + return this; } diff --git "a/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/package.json" "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/package.json" new file mode 100644 index 0000000..9ef4e93 --- /dev/null +++ "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/package.json" @@ -0,0 +1,7 @@ +{ + "main": "index.js", + "type": "module", + "scripts": { + "test": "node ./test.js" + } +} \ No newline at end of file diff --git "a/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/test.js" "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/test.js" new file mode 100644 index 0000000..4c45b48 --- /dev/null +++ "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/test.js" @@ -0,0 +1,75 @@ +import { DoubleLinkedList } from "./index.js"; + +function expect(string = "", cb) { + if (!new.target) { + return new expect(string, cb); + } + + this.isNot = false; + + Object.defineProperty(this, 'not', { + get() { + this.isNot = !this.isNot; + return this; + }, + }); + + this.toBeEqual = (val) => { + const res = cb(); + const result = this.isNot ? res !== val : res === val; + + const nowIsNot = this.isNot; + + this.isNot = false; + + console.log({ command: string, result, ...(!result ? { expectedValue: `${nowIsNot ? 'not ' : ''}${val}`, actualValue: res } : {}) }); + return result; + } +} + +try { + const tests = [ + expect("3개를 추가한 후 현재를 반환하면, 길이가 3개가 나와야 한다.", () => { + const doubleLinkedList = new DoubleLinkedList(); + return doubleLinkedList.insert(1).insert(2).insert(3).length; + }).toBeEqual(3), + expect("마지막을 삭제하면, 마지막은 첫번째 머리 노드가 나와야 한다.", () => { + const doubleLinkedList = new DoubleLinkedList(); + return doubleLinkedList.insert(1).insert(2).insert(3).remove().nowNode.val; + }).toBeEqual(1), + expect("첫번째 머리 노드를 삭제하면, 추출 시 다음 노드의 앞은 꼬리 노드가 나와야 한다.", () => { + const doubleLinkedList = new DoubleLinkedList(); + return doubleLinkedList.insert(1).insert(2).insert(3).goPrev().goPrev().remove().nowNode.val; + }).toBeEqual(2), + expect("첫번째 머리 노드를 삭제하면, 다음 머리는 다음 노드가 되어야 한다.", () => { + const doubleLinkedList = new DoubleLinkedList(); + return doubleLinkedList.insert(1).insert(2).insert(3).goPrev().goPrev().remove().head.val; + }).toBeEqual(2), + expect("getNthNodeFromHead 메서드로 순회를 한다면 머리 노드를 기준으로 나와야 한다", () => { + const doubleLinkedList = new DoubleLinkedList(); + return doubleLinkedList + .insert(1) + .insert(2) + .insert(3) + .insert(4) + .insert(5) + .insert(6) + .insert(7) + .insert(8) + .insert(9) + .getNthNode(8) + .val + }).toBeEqual(8) + ]; + + const res = tests.filter(v => v).length; + if (res === tests.length) { + console.log(`✅ CHECKED ${tests.length} TESTS SUCCEED!`) + } else { + throw new Error(`🔥 ${res}/${tests.length} TESTS SUCCEED. FAILED 😖`) + } + +} catch(e) { + console.error("🤯 FAILED TEST!\n") + console.error(e) +} \ No newline at end of file From 4c86ee1023add03876eb308f199adcc315960b7b Mon Sep 17 00:00:00 2001 From: JengYoung Date: Tue, 29 Nov 2022 23:59:31 +0900 Subject: [PATCH 3/4] =?UTF-8?q?:recycle:=20expect=EB=A5=BC=20=EA=B7=B8?= =?UTF-8?q?=EB=A3=B9=ED=99=94=ED=95=98=EC=97=AC=20=EA=B2=80=EC=82=AC?= =?UTF-8?q?=ED=95=98=EB=8A=94=20describe=20=ED=95=A8=EC=88=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\354\236\254\354\230\201/test.js" | 90 ++++++++++--------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git "a/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/test.js" "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/test.js" index 4c45b48..92a2fed 100644 --- "a/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/test.js" +++ "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/test.js" @@ -27,49 +27,51 @@ function expect(string = "", cb) { } } -try { - const tests = [ - expect("3개를 추가한 후 현재를 반환하면, 길이가 3개가 나와야 한다.", () => { - const doubleLinkedList = new DoubleLinkedList(); - return doubleLinkedList.insert(1).insert(2).insert(3).length; - }).toBeEqual(3), - expect("마지막을 삭제하면, 마지막은 첫번째 머리 노드가 나와야 한다.", () => { - const doubleLinkedList = new DoubleLinkedList(); - return doubleLinkedList.insert(1).insert(2).insert(3).remove().nowNode.val; - }).toBeEqual(1), - expect("첫번째 머리 노드를 삭제하면, 추출 시 다음 노드의 앞은 꼬리 노드가 나와야 한다.", () => { - const doubleLinkedList = new DoubleLinkedList(); - return doubleLinkedList.insert(1).insert(2).insert(3).goPrev().goPrev().remove().nowNode.val; - }).toBeEqual(2), - expect("첫번째 머리 노드를 삭제하면, 다음 머리는 다음 노드가 되어야 한다.", () => { - const doubleLinkedList = new DoubleLinkedList(); - return doubleLinkedList.insert(1).insert(2).insert(3).goPrev().goPrev().remove().head.val; - }).toBeEqual(2), - expect("getNthNodeFromHead 메서드로 순회를 한다면 머리 노드를 기준으로 나와야 한다", () => { - const doubleLinkedList = new DoubleLinkedList(); - return doubleLinkedList - .insert(1) - .insert(2) - .insert(3) - .insert(4) - .insert(5) - .insert(6) - .insert(7) - .insert(8) - .insert(9) - .getNthNode(8) - .val - }).toBeEqual(8) - ]; - - const res = tests.filter(v => v).length; - if (res === tests.length) { - console.log(`✅ CHECKED ${tests.length} TESTS SUCCEED!`) - } else { - throw new Error(`🔥 ${res}/${tests.length} TESTS SUCCEED. FAILED 😖`) +function describe(title, tests) { + try { + console.log(`${title} 결과: `) + const res = tests.filter(v => v).length; + if (res === tests.length) { + console.log(`✅ CHECKED ${tests.length} TESTS SUCCEED!`) + } else { + throw new Error(`🔥 ${res}/${tests.length} TESTS SUCCEED. FAILED 😖`) + } + } catch(e) { + console.error("🤯 FAILED TEST!\n") + console.error(e) } +} -} catch(e) { - console.error("🤯 FAILED TEST!\n") - console.error(e) -} \ No newline at end of file +describe("양방향 연결리스트", [ + expect("3개를 추가한 후 현재를 반환하면, 길이가 3개가 나와야 한다.", () => { + const doubleLinkedList = new DoubleLinkedList(); + return doubleLinkedList.insert(1).insert(2).insert(3).length; + }).toBeEqual(3), + expect("마지막을 삭제하면, 마지막은 첫번째 머리 노드가 나와야 한다.", () => { + const doubleLinkedList = new DoubleLinkedList(); + return doubleLinkedList.insert(1).insert(2).insert(3).remove().nowNode.val; + }).toBeEqual(1), + expect("첫번째 머리 노드를 삭제하면, 추출 시 다음 노드의 앞은 꼬리 노드가 나와야 한다.", () => { + const doubleLinkedList = new DoubleLinkedList(); + return doubleLinkedList.insert(1).insert(2).insert(3).goPrev().goPrev().remove().nowNode.val; + }).toBeEqual(2), + expect("첫번째 머리 노드를 삭제하면, 다음 머리는 다음 노드가 되어야 한다.", () => { + const doubleLinkedList = new DoubleLinkedList(); + return doubleLinkedList.insert(1).insert(2).insert(3).goPrev().goPrev().remove().head.val; + }).toBeEqual(2), + expect("getNthNodeFromHead 메서드로 순회를 한다면 머리 노드를 기준으로 나와야 한다", () => { + const doubleLinkedList = new DoubleLinkedList(); + return doubleLinkedList + .insert(1) + .insert(2) + .insert(3) + .insert(4) + .insert(5) + .insert(6) + .insert(7) + .insert(8) + .insert(9) + .getNthNode(8) + .val + }).toBeEqual(8) +]); \ No newline at end of file From 90c003ea71f1a2716dd8e988f18dba0c950e3f45 Mon Sep 17 00:00:00 2001 From: JengYoung Date: Wed, 30 Nov 2022 00:03:10 +0900 Subject: [PATCH 4/4] =?UTF-8?q?:memo:=20=EA=B3=BC=EC=A0=9C=20=EC=A0=9C?= =?UTF-8?q?=EC=B6=9C=20=EC=9C=84=ED=95=9C=20=EB=A6=AC=EB=93=9C=EB=AF=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assignment/\354\236\254\354\230\201/README.md" | 7 +++++++ 1 file changed, 7 insertions(+) diff --git "a/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/README.md" "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/README.md" index 882fc4c..bb78317 100644 --- "a/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/README.md" +++ "b/JavaScript/07\354\243\274\354\260\250/assignment/\354\236\254\354\230\201/README.md" @@ -29,3 +29,10 @@ yarn test ### 테스트 코드 작성 +`test.js`에서 테스트가 가능합니다. + +#### 작성 방법 + +`expect`가 같은 것임을 확인하는 함수라면, `describe`는 일련의 `expect`를 단위로 묶어주는 grouping을 위한 함수입니다. + +`describe`에 첫 번째 인자는 `"테스트 그룹명"`을, 두 번째 인자에는 `expect들의 배열`을 넣어주세요. \ No newline at end of file