diff --git a/README.md b/README.md index 51abd25..36bb89b 100644 --- a/README.md +++ b/README.md @@ -1 +1,92 @@ -# javascript-subway-final \ No newline at end of file +# ๐Ÿš‡ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ฒฝ๋กœ ์กฐํšŒ ๋ฏธ์…˜ + +- ๋“ฑ๋ก๋œ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„์—์„œ ๊ฒฝ๋กœ๋ฅผ ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ๋‹ค. + +### URL + +#### https://yungo1846.github.io/javascript-subway-path-precourse/ + +### ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ + +```bash +โ”‚ index.html +โ”‚ README.md +โ”‚ +โ”œโ”€images +โ”‚ dijkstra_example.png +โ”‚ path_result.gif +โ”‚ path_result.jpg +โ”‚ +โ””โ”€src + โ”‚ index.js + โ”‚ + โ”œโ”€common + โ”‚ alertMessage.js + โ”‚ checkInput.js + โ”‚ constant.js + โ”‚ StationInfo.js + โ”‚ + โ”œโ”€events + โ”‚ FindRoadEvent.js + โ”‚ + โ”œโ”€renders + โ”‚ renderRoadResult.js + โ”‚ + โ””โ”€utils + Dijkstra.js +``` + +### ์ดˆ๊ธฐ ์„ค์ • + +- ํ”„๋กœ๊ทธ๋žจ ์‹œ์ž‘ ์‹œ ์—ญ, ๋…ธ์„ , ๊ตฌ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐ ์„ค์ • ํ•ด์•ผ ํ•œ๋‹ค. +- ๊ฑฐ๋ฆฌ์™€ ์†Œ์š” ์‹œ๊ฐ„์€ ์–‘์˜ ์ •์ˆ˜์ด๋ฉฐ ๋‹จ์œ„๋Š” km์™€ ๋ถ„์„ ์˜๋ฏธํ•œ๋‹ค. +- ์•„๋ฌด ์—ญ๊ณผ๋„ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์€ '์•„ํ˜„์—ญ' ์ถ”๊ฐ€ (์˜ˆ์™ธ์‚ฌํ•ญ ํ…Œ์ŠคํŠธ์šฉ) +- ์•„๋ž˜์˜ ์‚ฌ์ „ ๋“ฑ๋ก ์ •๋ณด๋กœ ๋ฐ˜๋“œ์‹œ ์ดˆ๊ธฐ ์„ค์ •์„ ํ•œ๋‹ค. + +``` +1. ์ง€ํ•˜์ฒ ์—ญ์œผ๋กœ ๊ต๋Œ€, ๊ฐ•๋‚จ, ์—ญ์‚ผ, ๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„, ์–‘์žฌ, ์–‘์žฌ์‹œ๋ฏผ์˜์ˆฒ, ๋งค๋ด‰ ์—ญ ์ •๋ณด๊ฐ€ ๋“ฑ๋ก๋˜์–ด ์žˆ๋‹ค. +2. ์ง€ํ•˜์ฒ  ๋…ธ์„ ์œผ๋กœ 2ํ˜ธ์„ , 3ํ˜ธ์„ , ์‹ ๋ถ„๋‹น์„ ์ด ๋“ฑ๋ก๋˜์–ด ์žˆ๋‹ค. +3. ๋…ธ์„ ์— ์—ญ์ด ์•„๋ž˜์™€ ๊ฐ™์ด ๋“ฑ๋ก๋˜์–ด ์žˆ๋‹ค.(์™ผ์ชฝ ๋์ด ์ƒํ–‰ ์ข…์ ) + - 2ํ˜ธ์„ : ๊ต๋Œ€ - ( 2km / 3๋ถ„ ) - ๊ฐ•๋‚จ - ( 2km / 3๋ถ„ ) - ์—ญ์‚ผ + - 3ํ˜ธ์„ : ๊ต๋Œ€ - ( 3km / 2๋ถ„ ) - ๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„ - ( 6km / 5๋ถ„ ) - ์–‘์žฌ - ( 1km / 1๋ถ„ ) - ๋งค๋ด‰ + - ์‹ ๋ถ„๋‹น์„ : ๊ฐ•๋‚จ - ( 2km / 8๋ถ„ ) - ์–‘์žฌ - ( 10km / 3๋ถ„ ) - ์–‘์žฌ์‹œ๋ฏผ์˜์ˆฒ + - ์•„ํ˜„์—ญ +``` + +### ๊ฒฝ๋กœ ์กฐํšŒ ๊ธฐ๋Šฅ + + + +- ์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์„ ์ž…๋ ฅ๋ฐ›์•„ ๊ฒฝ๋กœ๋ฅผ ์กฐํšŒํ•œ๋‹ค. (์™„๋ฃŒ) +- ๊ฒฝ๋กœ ์กฐํšŒ ์‹œ ์ด ๊ฑฐ๋ฆฌ, ์ด ์†Œ์š” ์‹œ๊ฐ„์„ ํ•จ๊ป˜ ์ถœ๋ ฅํ•œ๋‹ค. (์™„๋ฃŒ) +- ๊ฒฝ๋กœ ์กฐํšŒ ์‹œ `์ตœ๋‹จ ๊ฑฐ๋ฆฌ` ๋˜๋Š” `์ตœ์†Œ ์‹œ๊ฐ„` ์˜ต์…˜์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค. (์™„๋ฃŒ) + +### ์˜ˆ์™ธ ์ฒ˜๋ฆฌ + +- ์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์€ 2๊ธ€์ž ์ด์ƒ์ด์–ด์•ผ ํ•œ๋‹ค. (์™„๋ฃŒ) +- ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์—ญ์„ ์ถœ๋ฐœ์—ญ ๋˜๋Š” ๋„์ฐฉ์—ญ์œผ๋กœ ์ž…๋ ฅํ•  ์ˆ˜ ์—†๋‹ค. (์™„๋ฃŒ) +- ๊ฒฝ๋กœ ์กฐํšŒ ์‹œ ์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ๊ฐ™์„ ์ˆ˜ ์—†๋‹ค. (์™„๋ฃŒ) +- ๊ฒฝ๋กœ ์กฐํšŒ ์‹œ ์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์œผ๋ฉด ๊ฒฝ๋กœ๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์—†๋‹ค. (์™„๋ฃŒ) + + => ๊ธฐ๋ณธ ๋…ธ์„  ์ •๋ณด์— ์•„๋ฌด ์—ญ๊ณผ๋„ ์—ฐ๊ฒฐ๋˜์žˆ์ง€ ์•Š์€ ์•„ํ˜„์—ญ์„ ์ž…๋ ฅํ•˜์—ฌ ํ™•์ธ ๊ฐ€๋Šฅ + +- ๊ทธ ์™ธ ์ •์ƒ์ ์œผ๋กœ ํ”„๋กœ๊ทธ๋žจ์ด ์ˆ˜ํ–‰๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ `alert`์œผ๋กœ ์—๋Ÿฌ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. (์™„๋ฃŒ) + +
+ +## ๐Ÿ’ป ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์‹คํ–‰ ๊ฒฐ๊ณผ + +### ๊ฒฝ๋กœ ์กฐํšŒ + + + +## โœ… ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์š”๊ตฌ์‚ฌํ•ญ + +### ๊ธธ์ฐพ๊ธฐ ๊ด€๋ จ ๊ธฐ๋Šฅ + +- ์ถœ๋ฐœ์—ญ์„ ์ž…๋ ฅํ•˜๋Š” input ํƒœ๊ทธ๋Š” `departure-station-name-input` id ์†์„ฑ๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- ๋„์ฐฉ์—ญ์„ ์ž…๋ ฅํ•˜๋Š” input ํƒœ๊ทธ๋Š” `arrival-station-name-input` id ์†์„ฑ๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- ์ตœ๋‹จ๊ฑฐ๋ฆฌ, ์ตœ์†Œ์‹œ๊ฐ„์„ ์„ ํƒํ•˜๋Š” radio๋Š” `search-type` name ์†์„ฑ๊ฐ’์„ ๊ฐ€์ง„๋‹ค. + - **radio option์˜ default ๊ฐ’์€ ์ตœ๋‹จ๊ฑฐ๋ฆฌ์ด๋‹ค.** +- ๊ธธ์ฐพ๊ธฐ ๋ฒ„ํŠผ์€ `search-button` id ์†์„ฑ๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- ๐Ÿ“ ๊ฒฐ๊ณผ๋Š” `table`์„ ์ด์šฉํ•˜์—ฌ ๋ณด์—ฌ์ค€๋‹ค. diff --git a/images/dijkstra_example.png b/images/dijkstra_example.png new file mode 100644 index 0000000..7c75197 Binary files /dev/null and b/images/dijkstra_example.png differ diff --git a/images/path_result.gif b/images/path_result.gif new file mode 100644 index 0000000..ee394bd Binary files /dev/null and b/images/path_result.gif differ diff --git a/images/path_result.jpg b/images/path_result.jpg new file mode 100644 index 0000000..40a4bed Binary files /dev/null and b/images/path_result.jpg differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..468a5fb --- /dev/null +++ b/index.html @@ -0,0 +1,37 @@ + + + + + ์ง€ํ•˜์ฒ  ๊ธธ์ฐพ๊ธฐ + + +
+

๐Ÿš‡ ์ง€ํ•˜์ฒ  ๊ธธ์ฐพ๊ธฐ

+
+

+ ์ถœ๋ฐœ์—ญ + +

+

+ ๋„์ฐฉ์—ญ + +

+

+ + + + +

+ +
+
+
+ + + diff --git a/src/common/StationInfo.js b/src/common/StationInfo.js new file mode 100644 index 0000000..e1deedc --- /dev/null +++ b/src/common/StationInfo.js @@ -0,0 +1,36 @@ +export const stations = [ + { name: "๊ต๋Œ€" }, + { name: "๊ฐ•๋‚จ" }, + { name: "์—ญ์‚ผ" }, + { name: "๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„" }, + { name: "์–‘์žฌ" }, + { name: "๋งค๋ด‰" }, + { name: "์–‘์žฌ์‹œ๋ฏผ์˜์ˆฒ" }, + { name: "์•„ํ˜„" }, // island node to test none connected stations +]; + +// sections: [์ถœ๋ฐœ์—ญ, ๋‹ค์Œ์—ญ, ๊ฑฐ๋ฆฌ, ์†Œ์š”์‹œ๊ฐ„] +export const lines = [ + { + name: "2ํ˜ธ์„ ", + sections: [ + ["๊ต๋Œ€", "๊ฐ•๋‚จ", 2, 3], + ["๊ฐ•๋‚จ", "์—ญ์‚ผ", 2, 3], + ], + }, + { + name: "3ํ˜ธ์„ ", + sections: [ + ["๊ต๋Œ€", "๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„", 3, 2], + ["๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„", "์–‘์žฌ", 6, 5], + ["์–‘์žฌ", "๋งค๋ด‰", 1, 1], + ], + }, + { + name: "์‹ ๋ถ„๋‹น์„ ", + sections: [ + ["๊ฐ•๋‚จ", "์–‘์žฌ", 2, 8], + ["์–‘์žฌ", "์–‘์žฌ์‹œ๋ฏผ์˜์ˆฒ", 10, 3], + ], + }, +]; diff --git a/src/common/alertMessage.js b/src/common/alertMessage.js new file mode 100644 index 0000000..a50671b --- /dev/null +++ b/src/common/alertMessage.js @@ -0,0 +1,9 @@ +import { constant } from "./constant.js"; + +export const alertMessage = { + SHORT_LENGTH_ERROR: `์—ญ ์ด๋ฆ„์€ ์ตœ์†Œ ${constant.minLength} ๊ธ€์ž ์ด์ƒ ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.`, + SAME_DESTINATION_ERROR: `์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ๊ฐ™์Šต๋‹ˆ๋‹ค`, + NONE_SELECTED_RADIO: `์ตœ๋‹จ๊ฑฐ๋ฆฌ์™€ ์ตœ์†Œ์‹œ๊ฐ„ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด์ฃผ์„ธ์š”!`, + NOT_EXIST_STATION: `์กด์žฌํ•˜์ง€ ์•Š๋Š” ์—ญ์ด ์ž…๋ ฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`, + NOT_CONNECTED_LINE: `์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ์„œ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.`, +}; diff --git a/src/common/checkInput.js b/src/common/checkInput.js new file mode 100644 index 0000000..a65cc47 --- /dev/null +++ b/src/common/checkInput.js @@ -0,0 +1,18 @@ +import { constant } from "./constant.js"; +export function isSatisfyLength(len) { + if (String(len).length < constant.minLength) { + return false; + } + + return true; +} + +export function isExistStation(stations, station) { + for (let i = 0; i < stations.length; i++) { + if (station === stations[i].name) { + return true; + } + } + + return false; +} diff --git a/src/common/constant.js b/src/common/constant.js new file mode 100644 index 0000000..c8f9579 --- /dev/null +++ b/src/common/constant.js @@ -0,0 +1,3 @@ +export const constant = { + minLength: 2, +}; diff --git a/src/events/FindRoadEvent.js b/src/events/FindRoadEvent.js new file mode 100644 index 0000000..3d9b0ad --- /dev/null +++ b/src/events/FindRoadEvent.js @@ -0,0 +1,126 @@ +import Dijkstra from "../utils/Dijkstra.js"; +import renderRoadResult from "../renders/renderRoadResult.js"; +import { alertMessage } from "../common/alertMessage.js"; +import { stations, lines } from "../common/StationInfo.js"; +import { isSatisfyLength, isExistStation } from "../common/checkInput.js"; + +export default function FindRoadEvent() { + const dijkstra = new Dijkstra(); + const startStation = document.getElementById("departure-station-name-input").value; + const endStation = document.getElementById("arrival-station-name-input").value; + const information = whichRadioChecked(); + if (!isValidInput()) { + return; + } + const shortestPath = getShortestPath(startStation, endStation); + if (!isStationsConneted()) { + return; + } + const totalWeight = getShortestWeight(shortestPath); + const totalDistance = totalWeight[0]; + const totalTime = totalWeight[1]; + renderRoadResult(information, shortestPath, totalDistance, totalTime); + + function isValidInput() { + if (!isSatisfyLength(startStation) || !isSatisfyLength(endStation)) { + alert(alertMessage.SHORT_LENGTH_ERROR); + return false; + } else if (startStation === endStation) { + alert(alertMessage.SAME_DESTINATION_ERROR); + return false; + } else if (!isExistStation(stations, startStation) || !isExistStation(stations, endStation)) { + alert(alertMessage.NOT_EXIST_STATION); + return false; + } else if (information === undefined) { + alert(alertMessage.NONE_SELECTED_RADIO); + return false; + } + return true; + } + + function whichRadioChecked() { + const shortestPathRadio = document.getElementById("shortest-path-radio"); + const minTimeRadio = document.getElementById("min-time-path-radio"); + + if (shortestPathRadio.checked) { + return shortestPathRadio.value; + } else if (minTimeRadio.checked) { + return minTimeRadio.value; + } else { + return undefined; + } + } + + function isStationsConneted() { + if (shortestPath === undefined) { + alert(alertMessage.NOT_CONNECTED_LINE); + return false; + } + return true; + } + + function _getShortestPath(i, j, index) { + for (let k = 0; k < lines[j].sections.length; k++) { + if (stations[i].name === lines[j].sections[k][0]) { + dijkstra.addEdge( + lines[j].sections[k][0], + lines[j].sections[k][1], + lines[j].sections[k][index] + ); + } + } + } + + function getShortestPath(start, end) { + let index; + if (information == "์ตœ๋‹จ๊ฑฐ๋ฆฌ") { + index = 2; + } else if (information == "์ตœ์†Œ์‹œ๊ฐ„") { + index = 3; + } + for (let i = 0; i < stations.length; i++) { + for (let j = 0; j < lines.length; j++) { + _getShortestPath(i, j, index); + } + } + + return dijkstra.findShortestPath(start, end); + } + + function _getShortestWeight(shortestPath, i, j) { + let _distance = 0; + let _time = 0; + for (let k = 0; k < lines[j].sections.length; k++) { + if ( + lines[j].sections[k][0] === shortestPath[i] && + lines[j].sections[k][1] === shortestPath[i + 1] + ) { + _distance += lines[j].sections[k][2]; + _time += lines[j].sections[k][3]; + } else if ( + lines[j].sections[k][1] === shortestPath[i] && + lines[j].sections[k][0] === shortestPath[i + 1] + ) { + _distance += lines[j].sections[k][2]; + _time += lines[j].sections[k][3]; + } + } + + return [_distance, _time]; + } + + function getShortestWeight(shortestPath) { + let distance = 0; + let time = 0; + let temp; + for (let i = 0; i < shortestPath.length; i++) { + for (let j = 0; j < lines.length; j++) { + temp = _getShortestWeight(shortestPath, i, j); + distance += temp[0]; + time += temp[1]; + } + } + + return [distance, time]; + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..95ad37a --- /dev/null +++ b/src/index.js @@ -0,0 +1,8 @@ +import FindRoadEvent from "./events/FindRoadEvent.js"; + +export default function SubwayNavigation() { + const inputButton = document.getElementById("search-button"); + inputButton.addEventListener("click", FindRoadEvent); +} + +new SubwayNavigation(); diff --git a/src/renders/renderRoadResult.js b/src/renders/renderRoadResult.js new file mode 100644 index 0000000..3efdf92 --- /dev/null +++ b/src/renders/renderRoadResult.js @@ -0,0 +1,46 @@ +function resultContainerTemplate(information, result) { + return `

๐Ÿ“‘๊ฒฐ๊ณผ

+

${information}

+ + + + + +
์ด ๊ฑฐ๋ฆฌ์ด ์†Œ์š” ์‹œ๊ฐ„
`; +} + +function initResultContainer(information) { + const resultContainer = document.getElementById("result-container"); + resultContainer.innerHTML = resultContainerTemplate(information); +} + +function resultListTemplate(shortestPath, totalDistance, totalTime) { + return ` + + ${totalDistance}Km + + + ${totalTime}๋ถ„ + + + + + ${shortestPath + .map((station, i) => (i !== shortestPath.length - 1 ? station + "=>" : station)) + .join("")} + + `; +} + +function initResultList(shortestPath, totalDistance, totalTime) { + const resultTable = document.getElementById("result-table"); + resultTable.insertAdjacentHTML( + "beforeend", + resultListTemplate(shortestPath, totalDistance, totalTime) + ); +} + +export default function renderRoadResult(information, shortestPath, totalDistance, totalTime) { + initResultContainer(information); + initResultList(shortestPath, totalDistance, totalTime); +} diff --git a/src/utils/Dijkstra.js b/src/utils/Dijkstra.js new file mode 100644 index 0000000..3cf4a81 --- /dev/null +++ b/src/utils/Dijkstra.js @@ -0,0 +1,212 @@ +export default function Dijkstra() { + const Node = { + init: function (val, priority) { + this.val = val; + this.priority = priority; + }, + }; + + const PriorityQueue = { + init: function () { + this.values = []; + }, + enqueue: function (val, priority) { + const newNode = Object.create(Node); + newNode.init(val, priority); + + this.values.push(newNode); + + let idxOfNewNode = this.values.length - 1; + + while (idxOfNewNode > 0) { + const idxOfParentNode = Math.floor((idxOfNewNode - 1) / 2); + + const parentNode = this.values[idxOfParentNode]; + + if (priority < parentNode.priority) { + this.values[idxOfParentNode] = newNode; + this.values[idxOfNewNode] = parentNode; + idxOfNewNode = idxOfParentNode; + continue; + } + break; + } + return this.values; + }, + dequeue: function () { + if (this.values.length == 0) { + return; + } + const dequeued = this.values.shift(); + const lastItem = this.values.pop(); + if (!lastItem) { + return dequeued; + } + this.values.unshift(lastItem); + + let idxOfTarget = 0; + + while (true) { + let idxOfLeftChild = idxOfTarget * 2 + 1; + let idxOfRightChild = idxOfTarget * 2 + 2; + let leftChild = this.values[idxOfLeftChild]; + let rightChild = this.values[idxOfRightChild]; + + function swap(direction) { + const idxOfChild = direction == "left" ? idxOfLeftChild : idxOfRightChild; + const child = direction == "left" ? leftChild : rightChild; + this.values[idxOfChild] = this.values[idxOfTarget]; + this.values[idxOfTarget] = child; + idxOfTarget = idxOfChild; + } + + if (!leftChild) { + return dequeued; + } + + if (!rightChild) { + if (leftChild.priority < lastItem.priority) { + swap.call(this, "left"); + continue; + } + return dequeued; + } + + if (leftChild.priority == rightChild.priority) { + swap.call(this, "left"); + continue; + } + + if (leftChild.priority < rightChild.priority && leftChild.priority < lastItem.priority) { + swap.call(this, "left"); + continue; + } + + if (rightChild.priority < leftChild.priority && rightChild.priority < lastItem.priority) { + swap.call(this, "right"); + continue; + } + } + }, + }; + + const WeightedGraph = { + init: function () { + this.adjacencyList = {}; + this.length = 0; + }, + addVertex: function (vertex) { + if (!this.adjacencyList.hasOwnProperty(vertex)) { + this.adjacencyList[vertex] = {}; + this.length++; + } + }, + addEdge: function (vertex1, vertex2, weight) { + this.addVertex(vertex1); + this.addVertex(vertex2); + this.adjacencyList[vertex1][vertex2] = weight; + this.adjacencyList[vertex2][vertex1] = weight; + return this.adjacencyList; + }, + removeEdge: function (vertex1, vertex2) { + if (!this.adjacencyList.hasOwnProperty(vertex1)) { + return `There's no ${vertex1}`; + } + if (!this.adjacencyList.hasOwnProperty(vertex2)) { + return `There's no ${vertex2}`; + } + + function removeHelper(v1, v2) { + if (!this.adjacencyList.hasOwnProperty(v1)) { + return `There's no edge between ${v1} and ${v2}`; + } + delete this.adjacencyList[v1][v2]; + if (Object.keys(this.adjacencyList[v1]).length == 0) { + delete this.adjacencyList[v1]; + } + } + + removeHelper.call(this, vertex1, vertex2); + removeHelper.call(this, vertex2, vertex1); + + return this.adjacencyList; + }, + removeVertex: function (vertex) { + if (!this.adjacencyList.hasOwnProperty(vertex)) { + return `There's no ${vertex}`; + } + const edges = this.adjacencyList[vertex]; + for (const key in edges) { + this.removeEdge(key, vertex); + } + return this.adjacencyList; + }, + findShortestRoute: function (start, end) { + if (!start || !end) { + throw Error("์ถœ๋ฐœ์ง€์™€ ๋„์ฐฉ์ง€๋ฅผ ๋ชจ๋‘ ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + const distance = {}; + const previous = {}; + const pq = Object.create(PriorityQueue); + pq.init(); + pq.enqueue(start, 0); + const visited = {}; + + const hashOfVertex = this.adjacencyList; + for (const vertexName in hashOfVertex) { + const priority = vertexName == start ? 0 : Infinity; + distance[vertexName] = priority; + previous[vertexName] = null; + } + + while (true) { + let current = pq.dequeue(); + if (!current?.val) { + return; + } + current = current.val; + if (current == end) { + break; + } + const neighbors = hashOfVertex[current]; + + for (const vertexName in neighbors) { + if (visited.hasOwnProperty(vertexName)) { + continue; + } + const distFromStart = distance[current] + neighbors[vertexName]; + + if (distFromStart < distance[vertexName]) { + pq.enqueue(vertexName, distFromStart); + distance[vertexName] = distFromStart; + previous[vertexName] = current; + } + } + visited[current] = true; + } + + let node = end; + + const route = []; + while (node) { + route.unshift(node); + node = previous[node]; + } + return route; + }, + }; + + this.addEdge = (source, target, weight) => { + WeightedGraph.addEdge(source, target, weight); + }; + + this.findShortestPath = (source, target) => { + return WeightedGraph.findShortestRoute(source, target); + }; + + this.addVertex = (vertex) => { + WeightedGraph.addVertex(vertex); + }; + + WeightedGraph.init(); +}