Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dsa-week4-assignment 윤영서 #1

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions problem-1/SymbolTableWithArray.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,84 @@
/*
다음은 비순차 심볼 테이블의 API입니다. 이 API를 지원하는 심볼 테이블을 구현해
주세요.
내부 데이터 구조는 순서가 없는 배열을 사용해서 구현해 주세요.

| 메서드 | 설명 |
| --- | --- |
| LinkedListST() | 심볼 테이블을 생성합니다 |
| get(key): Item? | 키와 연관된 값을 반환한다. 해당하는 키가 없으면 undefined를 반환 |
| put(key, value): void | 키/값 쌍을 테이블에 넣는다. |
| delete(key): void | 키에 해당하는 키/값 쌍을 삭제한다 |
| contains(key): Boolean | 키와 연관된 값이 존재하면 true, 존재하지 않으면 false를 반환한다 |
| isEmpty(): Boolean | 심볼 테이블이 비어있으면 true, 비어있지 않으면 false를 반환한다 |
| size(): Number | 테이블에 저장된 키/값 쌍의 개수를 반환한다 |
| keys(): Iterable | 테이블에 저장된 모든 키 목록 배열을 반환 |
| values(): Iterable | 테이블에 저장된 모든 값 목록 배열을 반환 |

*/
class SymbolTable {
#keys = [];
#values = [];
#n = 0;

constructor(maxCount = 10) {
this.#keys = new Array(maxCount);
this.#values = new Array(maxCount);
}

get(key) {
for (let i = 0; i < this.#n; i++) {
if (key === this.#keys[i]) {
return this.#values[i];
}
}
}

put(key, value) {
for (let i = 0; i < this.#n; i++) {
if (key === this.#keys[i]) {
this.#values[i] = value;
return;
}
}

this.#keys[this.#n] = key;
this.#values[this.#n] = value;
this.#n++;
}

delete(key) {
for (let i = 0; i < this.#n; i++) {
if (key === this.#keys[i]) {
for (let j = i; j < this.#n - 1; j++) {
this.#keys[j] = this.#keys[j + 1];
this.#values[j] = this.#values[j + 1];
}
this.#n--;
return;
}
}
}

contains(key) {
return !!this.get(key);
}

size() {
return this.#n;
}

isEmpty() {
return this.#n === 0;
}

keys() {
return this.#keys;
}

values() {
return this.#values;
}
Comment on lines +75 to +81
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

객체의 private속성인 키 목록과 값 목록을 접근할 수 있도록 메서드를 만들어 주셨네요.
객체 안에 있는 참조 타입을 외부로 그대로 반환하게 되면 캡슐화 원칙을 깨트릴 수 있어요. 예를들어서

class Something {
  #items = [];

  getItems() {
    return this.#items;
  }
}

const something = new Something();
const innerItems = something.getItems();
innerItems[0] = 'Hello';

console.log(something.getItems()); // ['Hello']

이런식으로 외부에서 값을 수정할 수 있게 되는거죠. 그래서 바깥으로 무언가를 전달할 때는 항상 방어적으로 작성해야 해요.

class Something {
  #items = [];

  getItems() {
    return [...this.#items]; // 복사해서 반환
  }
}

const something = new Something();
const innerItems = something.getItems();
innerItems[0] = 'Hello';

console.log(something.getItems()); // []

위와 같이 배열을 반환할 때 복사해서 반환하게 되면 아무리 반환된 값을 고치더라도 내부 데이터를 건드릴 수 없게 돼요. 이와 비슷하게 흔히 사용하는 방식중에 객체를 그대로 외부에서 사용할 수 있도록 할 때가 있는데요.

export const defaultOwnerData = {
  firstName: "Martin",
  lastName: "Fowler"
};

사실 더 안전하게 하려면 다음과 같이 해야합니다.

const �ownerData = {
  firstName: "Martin",
  lastName: "Fowler"
};

export const defaultOwnerData = { ...ownerData };

그러면 외부에서 값을 변경하더라도 원본 데이터는 변경되지 않습니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 그냥 프로퍼티 접근를 반환하는 getter setter만 있으면 방어적일 수 있다고 생각했는데, 저렇게 반환해줘야하는지 몰랐네요 ㅎㅎㅎ 감사합니다

}

module.exports = {
Expand Down
79 changes: 78 additions & 1 deletion problem-2/SymbolTable.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,37 @@
/**
*
*
다음은 순차 심볼 테이블의 API입니다.

| 메서드 | 설명 |
| --- | --- |
| ST() | 심볼 테이블을 생성합니다 |
| get(key): Item? | 키와 연관된 값을 반환한다. 해당하는 키가 없으면 undefined를 반환 |
| put(key, value): void | 키/값 쌍을 테이블에 넣는다. |
| delete(key): void | 키에 해당하는 키/값 쌍을 삭제한다 |
| contains(key): Boolean | 키와 연관된 값이 존재하면 true, 존재하지 않으면 false를 반환한다 |
| isEmpty(): Boolean | 심볼 테이블이 비어있으면 true, 비어있지 않으면 false를 반환한다 |
| size(): Number | 테이블에 저장된 키/값 쌍의 개수를 반환한다 |
| min(): Key? | 가장 작은 키를 반환한다 |
| max(): Key? | 가장 큰 키를 반환한다 |
| floor(Key): Key? | 키보다 작거나 같은 값 중에 가장 큰 키를 반환 |
| ceiling(Key): Key? | 주어진 키보다 크거나 같은 가장 작은 키를 반환 |
| rank(Key): Key? | 주어진 키보다 작은 키의 개수 반환 |
| select(k): Key? | k번째 순위의 키를 반환 |
| deleteMin(): void | 가장 작은 키를 삭제한다 |
| deleteMax(): void | 가장 큰 키를 삭제한다 |
| keys(): Iterable | 테이블에 저장된 모든 키 목록 배열을 반환 |
| keysRange(low, high): Iterable | [low..high] 범위에 속하는 키 목록 배열 반환 |

위 API를 참고하여 아래 기능들을 구현해 주세요. `rank()`를 활용해서 구현해야 합니다.

* contains
* floor
* ceiling
* keysRange

*/

class SymbolTable {
#keys;

Expand Down Expand Up @@ -71,7 +105,8 @@ class SymbolTable {
const mid = start + Math.floor((end - start) / 2);
if (key < this.#keys[mid]) {
return this.rank(key, start, mid - 1);
} if (key > this.#keys[mid]) {
}
if (key > this.#keys[mid]) {
return this.rank(key, mid + 1, end);
}
return mid;
Expand Down Expand Up @@ -106,15 +141,57 @@ class SymbolTable {
}

contains(key) {
return !!this.get(key);
}

floor(key) {
if (this.isEmpty()) {
return;
}
const i = this.rank(key);
if (i === 0) {
return this.#keys[i] === key ? key : undefined;
}

if (key === this.#keys[i]) {
return key;
}

return this.#keys[i - 1];
}

ceiling(key) {
if (this.isEmpty()) {
return;
}
const i = this.rank(key);
if (i >= this.#n) {
return;
}

return this.#keys[i];
}

keysRange(start, end) {
const startIndex = this.rank(start);
const endIndex = this.rank(end);

const array = [];

for (let i = startIndex; i < endIndex; i++) {
array.push(this.#keys[i]);
}

if (this.#keys[endIndex] === end) {
array.push(end);
}

return array;
/*
return endIndex === end
? this.#keys.slice(startIndex, endIndex )
: this.#keys.slice(startIndex, endIndex + 1);
*/
}
}

Expand Down
69 changes: 56 additions & 13 deletions problem-3/SymbolTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ class Node {

n;

constructor(key, value, n) {
height;

constructor(key, value, n, height = 0) {
this.key = key;
this.value = value;
this.n = n;
this.height = height;
}
}

Expand Down Expand Up @@ -46,7 +49,8 @@ class SymbolTable {

if (key < node.key) {
return this.#get(node.left, key);
} if (key > node.key) {
}
if (key > node.key) {
return this.#get(node.right, key);
}
return node.value;
Expand All @@ -70,6 +74,8 @@ class SymbolTable {
}

node.n = this.#size(node.left) + this.#size(node.right) + 1;
node.height =
1 + Math.max(this.#height(node.left), this.#height(node.right));
return node;
}

Expand All @@ -89,6 +95,22 @@ class SymbolTable {
return this.#max(this.#root).key;
}

#min(node) {
if (node.left === undefined) {
return node;
}

return this.#min(node.left);
}

#max(node) {
if (node.right === undefined) {
return node;
}

return this.#max(node.right);
}

floor(key) {
return this.#floor(this.#root, key)?.key;
}
Expand Down Expand Up @@ -143,7 +165,8 @@ class SymbolTable {
const t = this.#size(node.left);
if (t > k) {
return this.#select(node.left, k);
} if (t < k) {
}
if (t < k) {
return this.#select(node.right, k - t - 1);
}
return node;
Expand All @@ -160,7 +183,8 @@ class SymbolTable {

if (key < node.key) {
return this.#rank(node.left, key);
} if (key > node.key) {
}
if (key > node.key) {
return 1 + this.#size(node.left) + this.#rank(node.right, key);
}
return this.#size(node.left);
Expand All @@ -181,6 +205,8 @@ class SymbolTable {

node.left = this.#deleteMin(node.left);
node.n = this.#size(node.left) + this.#size(node.right) + 1;
node.height =
1 + Math.max(this.#height(node.left), this.#height(node.right));
return node;
}

Expand Down Expand Up @@ -213,6 +239,9 @@ class SymbolTable {
}

node.n = this.#size(node.left) + this.#size(node.right) + 1;

node.height =
1 + Math.max(this.#height(node.left), this.#height(node.right));
return node;
}

Expand Down Expand Up @@ -254,20 +283,34 @@ class SymbolTable {
}
}

#min(node) {
if (node.left === undefined) {
return node;
/**
*
*
2. 트리의 높이를 구하는 height를 구현해 주세요. 이때 2가지 버전의 구현을 만들어
주세요. 첫 번째는 재귀로 실행할 때마다 새로 계산해서 높이를 구하는 버전을
만들어 주세요. 두 번째는 `size()`와 비슷하게 각 노드에 트리의 높이를 담는
필드 변수를 활용해서 구현한 버전을 만들어 주세요.

*/
height() {
return this.#height(this.#root);
}

/*
#height(node) {
if (node === undefined) {
return -1;
}

return this.#min(node.left);
}
return 1 + Math.max(this.#height(node.left), this.#height(node.right));
}*/

#max(node) {
if (node.right === undefined) {
return node;
#height(node) {
if (node === undefined) {
return -1;
}

return this.#max(node.right);
return node.height;
}
}

Expand Down
Loading
Loading