├── .gitignore ├── README.md ├── docs ├── README_BAK.md └── print-binary-tree-with-preOrder-and-inOrder-traverse-result.md ├── index.js ├── package-lock.json ├── package.json ├── src ├── base │ ├── binary-search.ts │ ├── linked-list.ts │ ├── queue.ts │ └── stack.ts ├── index.ts └── js │ ├── bin-search.js │ ├── binary-tree.js │ ├── check-binary-tree-is-BST.js │ ├── doubly-linked-circual-list.js │ ├── doubly-linked-list.js │ ├── has-loop-in-linked-list.js │ ├── linked-list.js │ ├── list.js │ ├── max-distance-in-binary-tree.js │ ├── max-width-of-binary-tree.js │ ├── min-absolute-difference-in-binary-tree.js │ ├── min-depths-of-binary-tree.js │ ├── queue.js │ ├── reverse-binary-tree.js │ ├── self-organization-search.js │ ├── singly-linked-circular-list.js │ └── stack.js ├── tsconfig.json └── tslint.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # data-structures-and-algorithms-in-javascript 2 | 为前端工程师准备的数据结构和算法基础课,所有的数据结构和算法都通过`JavaScript`实现 3 | 4 | # 数据结构 5 | 6 | > 由于JavaScript对数据结构的支持先天不足,故此部分先通过JavaScript实现常用的数据结构,为后一节的算法实现做好准备。 7 | 线性数据结构: 数组、栈、队列、链表 8 | 非线性数据结构: 树、图、散列(哈希表)、堆 9 | 10 | * 数组 11 | > 数组的定义是一个用来存储元素的线性集合。通过索引来计算数据在这个集合中存储的位置。为了保证数据存储和访问的高效,索引在这里只能是数字,可以通过索引计算偏移量从而快速访问到真实数据在内存里的位置。 12 | 13 | 但是在javaScript中,数组使用了对象的方式来实现,数字索引在使用和存储的时候被转换成字符串类型。其实很好理解,从设计上来讲,数组完全可以用key值为数组index的对象来表达。 14 | 15 | * 栈 16 | > 栈可以简单理解为受限的数组,`栈是一种遵循后进先出(Last-In-First-Out, LIFO)的数据结构,每次只能访问或操作栈顶的元素`。类比到生活中,餐厅叠起来等待被清洗的盘子就是很形象的具象化表达。 17 | 18 | 对于栈,我们主要需要实现的方法包括: 入栈(push)、出栈(pop)、获取栈顶元素(peek) 19 | 20 | * 队列 21 | > 和栈类似,队列也可以理解为一种受限的数组,`队列是一种遵循先进先出(First-In-First-Out, FIFO)的数据结构,每次只能访问或操作队首的元素,并在队尾添加元素`。类比到生活中,银行里排队等待办理业务的人员就是很形象的具象化表达。先进入的先被处理,后进入的后被处理,只能按照顺序来。 22 | 23 | 对于队列,我们主要需要实现的方法包括: 出队(shift)、入队(push)、获取队头元素(peek) 24 | 25 | * 链表 26 | > `链表是一种物理存储单元上,非连续、非顺序的存储结构,各个元素之间通过本身的链(指针)来关联`。链表包括,单向链表、双向链表、循环链表。 27 | 类比数组,通过索引(偏移量)来关联,意味着数据必须存储在一段连续的存储空间里(这里只讨论数据结构定义里的数组),并且大小是固定的,否则通过偏移量来访问数据就不具有可靠性了。 28 | 链表通过本身的链(指针)来访问,每一个节点都记录着下一个节点的位置,不依赖存储的连续性和顺序性,访问的时候从链表的头节点按顺序访问到尾结点就可以了。 29 | 30 | 对于链表,我们需要实现链表的节点(node)、链表节点的插入(insert)、链表节点的删除(delete) 31 | 32 | * 树 33 | * 散列 34 | * 图 35 | 36 | * 堆 37 | # 算法 38 | -------------------------------------------------------------------------------- /docs/README_BAK.md: -------------------------------------------------------------------------------- 1 | # data-structures-and-algorithms-in-frontend 2 | 基本数据结构和算法的前端实现(the implementation of basic data structure and algorithm in JavaScript)[不断补充中] 3 | >> 4 | 推荐给前端工程师的参考书 **数据结构与算法JavaScript描述** 5 | 所有代码在`src/js`目录下 6 | 7 | # 数据结构 8 | 9 | ## 数组 10 | JavaScript已经内建对数组的支持,并且由于JavaScript的灵活性,相比较其他语言的数组,还具有更多的玩法,大家可以自己探索。 11 | 12 | ## 列表 13 | * 列表的实现(`list.js`) 14 | 列表的基本操作: 15 | * append(在尾部添加元素) 16 | * remove(从列表删除元素) 17 | * find(在列表中查找某项元素) 18 | * length(列表的长度) 19 | * toString(显示列表中的元素) 20 | * insert(向列表中插入一个元素) 21 | * clear(清空列表中所有元素) 22 | * contains(判断列表中是否存在给定值) 23 | 24 | 25 | ## 栈 26 | * 栈的实现(`stack.js`) 27 | 栈的基本操作: 28 | * push(入栈) 29 | * pop(出栈) 30 | * peek(返回栈顶元素) 31 | * clear(清空栈) 32 | * length(栈的长度) 33 | 34 | ## 队列 35 | * 队列的实现(`queue.js`) 36 | 队列的基本操作: 37 | * enqueue(向队尾添加元素) 38 | * dequeue(删除队首的元素) 39 | * front(读取队首元素) 40 | * back(读取队尾元素) 41 | * display(显示队列内所有元素) 42 | * isEmpty(判断队列是否为空) 43 | 44 | ## 树 45 | * 二叉树的实现(`binary-tree.js`) 46 | * 二叉查找树的实现(`binary-tree.js`) 47 | * 检查二叉树是否是二叉查找树(`check-binary-tree-is-BST.js`) 48 | * 查找二叉树节点间的最大距离(`max-distance-in-binary-tree.js`) 49 | * 查找二叉树的最大宽度(`max-width-of-binary-tree.js`) 50 | * 查找二叉树的最小深度(`min-depths-of-binary-tree.js`) 51 | * 查找二叉树节点间的最小差值(`min-absolute-difference-in-binary-tree.js`) 52 | * 镜像翻转二叉树(`reverse-binary-tree.js`) 53 | 54 | 55 | 56 | ## 链表 57 | * 单向链表的实现(`linked-list.js`) 58 | * 双向链表的实现(`doubly-linked-list.js`) 59 | * 单向循环链表的实现(`singly-linked-circular-list.js`) 60 | * 双向循环链表的实现(`doubly-linked-circular-list.js`) 61 | * 判断链表是否有环(`whether-exit-loop-in-linked-list.js`) 62 | 63 | 64 | # 算法 65 | ## 排序算法 66 | 排序算法在我的另一个总结里已经写得很详细了,这里就不重复写了。 67 | 请移步: [usualSortAlgorithm](https://github.com/ovenzeze/usualSortAlgorithm) 68 | ## 检索算法 69 | * 二分查找(`bin-serach.js`) 70 | * 自组织查找(`self-organization-search.js`) 71 | 72 | # 补充知识 73 | * 根据先序遍历和中序遍历结果画出二叉树(`print-binary-tree-with-preOrder-and-inOrder-traverse-result.md`) 74 | -------------------------------------------------------------------------------- /docs/print-binary-tree-with-preOrder-and-inOrder-traverse-result.md: -------------------------------------------------------------------------------- 1 | # 根据中序遍历和先序遍历结果画出二叉树 2 | >> 3 | 假设某二叉树的先序遍历序列是`abdgcefh`,中序遍历序列是`dgbaechf`,画出二叉树,并给出其后序遍历序列. 4 | 5 | # 分析: 6 | 先序遍历序列的第一个字符为根结点.对于中序遍历,根结点在中序遍历序列的中间,左边部分是根结点的左子树的中序遍历序列,右边部分是根结点的右子树的中序遍历序列. 7 | 8 | * 先序:abdgcefh --> a bdg cefh 9 | * 中序:dgbaechf --> dgb a echf 10 | 11 | **得出结论:** 12 | 13 | a是树根,a有左子树和右子树,左子树有bdg结点,右子树有cefh结点. 14 | * 先序:bdg --> b dg 15 | * 中序:dgb --> dg b 16 | 17 | **得出结论:** 18 | 19 | b是左子树的根结点,b无右子树,有左子树. 20 | * 先序:dg --> d g 21 | * 中序:dg --> d g 22 | 23 | **得出结论:** 24 | 25 | d是b的左子树的根结点,d无左子树,有右子树. 26 | * 先序:cefh --> c e fh 27 | * 中序:echf --> e c hf 28 | 29 | **得出结论:** 30 | 31 | c是右子树的根结点,c有左子树(只有e结点),有右子树(有fh结点). 32 | * 先序:fh --> f h 33 | * 中序:hf --> h f 34 | 35 | **得出结论:** 36 | 37 | f是c的左子树的根结点,f有左子树(只有h结点),无右子树. 38 | 39 | 还原二叉树为:(MarkDown实在不知道怎么画二叉树) 40 | 41 | -----------a 42 | 43 | ------b-----------c 44 | 45 | d----------e-------------f 46 | 47 | -----g-------------h 48 | 49 | 后序遍历序列:gdbehfca 50 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('./dist/index.js'); -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "data-structures-and-algorithms-in-javascript", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.5.5", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", 10 | "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.0.0" 14 | } 15 | }, 16 | "@babel/highlight": { 17 | "version": "7.5.0", 18 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", 19 | "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", 20 | "dev": true, 21 | "requires": { 22 | "chalk": "^2.0.0", 23 | "esutils": "^2.0.2", 24 | "js-tokens": "^4.0.0" 25 | } 26 | }, 27 | "abbrev": { 28 | "version": "1.1.1", 29 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 30 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", 31 | "dev": true 32 | }, 33 | "ansi-align": { 34 | "version": "2.0.0", 35 | "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", 36 | "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", 37 | "dev": true, 38 | "requires": { 39 | "string-width": "^2.0.0" 40 | } 41 | }, 42 | "ansi-regex": { 43 | "version": "3.0.0", 44 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 45 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 46 | "dev": true 47 | }, 48 | "ansi-styles": { 49 | "version": "3.2.1", 50 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 51 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 52 | "dev": true, 53 | "requires": { 54 | "color-convert": "^1.9.0" 55 | } 56 | }, 57 | "anymatch": { 58 | "version": "3.1.1", 59 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", 60 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", 61 | "dev": true, 62 | "requires": { 63 | "normalize-path": "^3.0.0", 64 | "picomatch": "^2.0.4" 65 | } 66 | }, 67 | "argparse": { 68 | "version": "1.0.10", 69 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 70 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 71 | "dev": true, 72 | "requires": { 73 | "sprintf-js": "~1.0.2" 74 | } 75 | }, 76 | "balanced-match": { 77 | "version": "1.0.0", 78 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 79 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 80 | "dev": true 81 | }, 82 | "binary-extensions": { 83 | "version": "2.0.0", 84 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", 85 | "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", 86 | "dev": true 87 | }, 88 | "boxen": { 89 | "version": "1.3.0", 90 | "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", 91 | "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", 92 | "dev": true, 93 | "requires": { 94 | "ansi-align": "^2.0.0", 95 | "camelcase": "^4.0.0", 96 | "chalk": "^2.0.1", 97 | "cli-boxes": "^1.0.0", 98 | "string-width": "^2.0.0", 99 | "term-size": "^1.2.0", 100 | "widest-line": "^2.0.0" 101 | } 102 | }, 103 | "brace-expansion": { 104 | "version": "1.1.11", 105 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 106 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 107 | "dev": true, 108 | "requires": { 109 | "balanced-match": "^1.0.0", 110 | "concat-map": "0.0.1" 111 | } 112 | }, 113 | "braces": { 114 | "version": "3.0.2", 115 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 116 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 117 | "dev": true, 118 | "requires": { 119 | "fill-range": "^7.0.1" 120 | } 121 | }, 122 | "builtin-modules": { 123 | "version": "1.1.1", 124 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 125 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 126 | "dev": true 127 | }, 128 | "camelcase": { 129 | "version": "4.1.0", 130 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", 131 | "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", 132 | "dev": true 133 | }, 134 | "capture-stack-trace": { 135 | "version": "1.0.1", 136 | "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", 137 | "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", 138 | "dev": true 139 | }, 140 | "chalk": { 141 | "version": "2.4.2", 142 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 143 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 144 | "dev": true, 145 | "requires": { 146 | "ansi-styles": "^3.2.1", 147 | "escape-string-regexp": "^1.0.5", 148 | "supports-color": "^5.3.0" 149 | } 150 | }, 151 | "chokidar": { 152 | "version": "3.3.1", 153 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", 154 | "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", 155 | "dev": true, 156 | "requires": { 157 | "anymatch": "~3.1.1", 158 | "braces": "~3.0.2", 159 | "fsevents": "~2.1.2", 160 | "glob-parent": "~5.1.0", 161 | "is-binary-path": "~2.1.0", 162 | "is-glob": "~4.0.1", 163 | "normalize-path": "~3.0.0", 164 | "readdirp": "~3.3.0" 165 | } 166 | }, 167 | "ci-info": { 168 | "version": "1.6.0", 169 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", 170 | "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", 171 | "dev": true 172 | }, 173 | "cli-boxes": { 174 | "version": "1.0.0", 175 | "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", 176 | "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", 177 | "dev": true 178 | }, 179 | "color-convert": { 180 | "version": "1.9.3", 181 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 182 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 183 | "dev": true, 184 | "requires": { 185 | "color-name": "1.1.3" 186 | } 187 | }, 188 | "color-name": { 189 | "version": "1.1.3", 190 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 191 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 192 | "dev": true 193 | }, 194 | "commander": { 195 | "version": "2.20.3", 196 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 197 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 198 | "dev": true 199 | }, 200 | "concat-map": { 201 | "version": "0.0.1", 202 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 203 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 204 | "dev": true 205 | }, 206 | "configstore": { 207 | "version": "3.1.2", 208 | "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", 209 | "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", 210 | "dev": true, 211 | "requires": { 212 | "dot-prop": "^4.1.0", 213 | "graceful-fs": "^4.1.2", 214 | "make-dir": "^1.0.0", 215 | "unique-string": "^1.0.0", 216 | "write-file-atomic": "^2.0.0", 217 | "xdg-basedir": "^3.0.0" 218 | } 219 | }, 220 | "create-error-class": { 221 | "version": "3.0.2", 222 | "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", 223 | "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", 224 | "dev": true, 225 | "requires": { 226 | "capture-stack-trace": "^1.0.0" 227 | } 228 | }, 229 | "cross-spawn": { 230 | "version": "5.1.0", 231 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", 232 | "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", 233 | "dev": true, 234 | "requires": { 235 | "lru-cache": "^4.0.1", 236 | "shebang-command": "^1.2.0", 237 | "which": "^1.2.9" 238 | } 239 | }, 240 | "crypto-random-string": { 241 | "version": "1.0.0", 242 | "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", 243 | "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", 244 | "dev": true 245 | }, 246 | "debug": { 247 | "version": "3.2.6", 248 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 249 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 250 | "dev": true, 251 | "requires": { 252 | "ms": "^2.1.1" 253 | } 254 | }, 255 | "deep-extend": { 256 | "version": "0.6.0", 257 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 258 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 259 | "dev": true 260 | }, 261 | "diff": { 262 | "version": "4.0.1", 263 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", 264 | "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", 265 | "dev": true 266 | }, 267 | "dot-prop": { 268 | "version": "4.2.0", 269 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", 270 | "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", 271 | "dev": true, 272 | "requires": { 273 | "is-obj": "^1.0.0" 274 | } 275 | }, 276 | "duplexer3": { 277 | "version": "0.1.4", 278 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", 279 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", 280 | "dev": true 281 | }, 282 | "escape-string-regexp": { 283 | "version": "1.0.5", 284 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 285 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 286 | "dev": true 287 | }, 288 | "esprima": { 289 | "version": "4.0.1", 290 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 291 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 292 | "dev": true 293 | }, 294 | "esutils": { 295 | "version": "2.0.3", 296 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 297 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 298 | "dev": true 299 | }, 300 | "execa": { 301 | "version": "0.7.0", 302 | "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", 303 | "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", 304 | "dev": true, 305 | "requires": { 306 | "cross-spawn": "^5.0.1", 307 | "get-stream": "^3.0.0", 308 | "is-stream": "^1.1.0", 309 | "npm-run-path": "^2.0.0", 310 | "p-finally": "^1.0.0", 311 | "signal-exit": "^3.0.0", 312 | "strip-eof": "^1.0.0" 313 | } 314 | }, 315 | "fill-range": { 316 | "version": "7.0.1", 317 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 318 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 319 | "dev": true, 320 | "requires": { 321 | "to-regex-range": "^5.0.1" 322 | } 323 | }, 324 | "fs.realpath": { 325 | "version": "1.0.0", 326 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 327 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 328 | "dev": true 329 | }, 330 | "fsevents": { 331 | "version": "2.1.2", 332 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", 333 | "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", 334 | "dev": true, 335 | "optional": true 336 | }, 337 | "get-stream": { 338 | "version": "3.0.0", 339 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", 340 | "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", 341 | "dev": true 342 | }, 343 | "glob": { 344 | "version": "7.1.6", 345 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 346 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 347 | "dev": true, 348 | "requires": { 349 | "fs.realpath": "^1.0.0", 350 | "inflight": "^1.0.4", 351 | "inherits": "2", 352 | "minimatch": "^3.0.4", 353 | "once": "^1.3.0", 354 | "path-is-absolute": "^1.0.0" 355 | } 356 | }, 357 | "glob-parent": { 358 | "version": "5.1.1", 359 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", 360 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", 361 | "dev": true, 362 | "requires": { 363 | "is-glob": "^4.0.1" 364 | } 365 | }, 366 | "global-dirs": { 367 | "version": "0.1.1", 368 | "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", 369 | "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", 370 | "dev": true, 371 | "requires": { 372 | "ini": "^1.3.4" 373 | } 374 | }, 375 | "got": { 376 | "version": "6.7.1", 377 | "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", 378 | "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", 379 | "dev": true, 380 | "requires": { 381 | "create-error-class": "^3.0.0", 382 | "duplexer3": "^0.1.4", 383 | "get-stream": "^3.0.0", 384 | "is-redirect": "^1.0.0", 385 | "is-retry-allowed": "^1.0.0", 386 | "is-stream": "^1.0.0", 387 | "lowercase-keys": "^1.0.0", 388 | "safe-buffer": "^5.0.1", 389 | "timed-out": "^4.0.0", 390 | "unzip-response": "^2.0.1", 391 | "url-parse-lax": "^1.0.0" 392 | } 393 | }, 394 | "graceful-fs": { 395 | "version": "4.2.3", 396 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", 397 | "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", 398 | "dev": true 399 | }, 400 | "has-flag": { 401 | "version": "3.0.0", 402 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 403 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 404 | "dev": true 405 | }, 406 | "ignore-by-default": { 407 | "version": "1.0.1", 408 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", 409 | "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", 410 | "dev": true 411 | }, 412 | "import-lazy": { 413 | "version": "2.1.0", 414 | "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", 415 | "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", 416 | "dev": true 417 | }, 418 | "imurmurhash": { 419 | "version": "0.1.4", 420 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 421 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 422 | "dev": true 423 | }, 424 | "inflight": { 425 | "version": "1.0.6", 426 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 427 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 428 | "dev": true, 429 | "requires": { 430 | "once": "^1.3.0", 431 | "wrappy": "1" 432 | } 433 | }, 434 | "inherits": { 435 | "version": "2.0.4", 436 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 437 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 438 | "dev": true 439 | }, 440 | "ini": { 441 | "version": "1.3.5", 442 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", 443 | "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", 444 | "dev": true 445 | }, 446 | "is-binary-path": { 447 | "version": "2.1.0", 448 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 449 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 450 | "dev": true, 451 | "requires": { 452 | "binary-extensions": "^2.0.0" 453 | } 454 | }, 455 | "is-ci": { 456 | "version": "1.2.1", 457 | "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", 458 | "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", 459 | "dev": true, 460 | "requires": { 461 | "ci-info": "^1.5.0" 462 | } 463 | }, 464 | "is-extglob": { 465 | "version": "2.1.1", 466 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 467 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 468 | "dev": true 469 | }, 470 | "is-fullwidth-code-point": { 471 | "version": "2.0.0", 472 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 473 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 474 | "dev": true 475 | }, 476 | "is-glob": { 477 | "version": "4.0.1", 478 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 479 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 480 | "dev": true, 481 | "requires": { 482 | "is-extglob": "^2.1.1" 483 | } 484 | }, 485 | "is-installed-globally": { 486 | "version": "0.1.0", 487 | "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", 488 | "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", 489 | "dev": true, 490 | "requires": { 491 | "global-dirs": "^0.1.0", 492 | "is-path-inside": "^1.0.0" 493 | } 494 | }, 495 | "is-npm": { 496 | "version": "1.0.0", 497 | "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", 498 | "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", 499 | "dev": true 500 | }, 501 | "is-number": { 502 | "version": "7.0.0", 503 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 504 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 505 | "dev": true 506 | }, 507 | "is-obj": { 508 | "version": "1.0.1", 509 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", 510 | "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", 511 | "dev": true 512 | }, 513 | "is-path-inside": { 514 | "version": "1.0.1", 515 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", 516 | "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", 517 | "dev": true, 518 | "requires": { 519 | "path-is-inside": "^1.0.1" 520 | } 521 | }, 522 | "is-redirect": { 523 | "version": "1.0.0", 524 | "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", 525 | "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", 526 | "dev": true 527 | }, 528 | "is-retry-allowed": { 529 | "version": "1.2.0", 530 | "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", 531 | "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", 532 | "dev": true 533 | }, 534 | "is-stream": { 535 | "version": "1.1.0", 536 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 537 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", 538 | "dev": true 539 | }, 540 | "isexe": { 541 | "version": "2.0.0", 542 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 543 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 544 | "dev": true 545 | }, 546 | "js-tokens": { 547 | "version": "4.0.0", 548 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 549 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 550 | "dev": true 551 | }, 552 | "js-yaml": { 553 | "version": "3.13.1", 554 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 555 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 556 | "dev": true, 557 | "requires": { 558 | "argparse": "^1.0.7", 559 | "esprima": "^4.0.0" 560 | } 561 | }, 562 | "latest-version": { 563 | "version": "3.1.0", 564 | "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", 565 | "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", 566 | "dev": true, 567 | "requires": { 568 | "package-json": "^4.0.0" 569 | } 570 | }, 571 | "lowercase-keys": { 572 | "version": "1.0.1", 573 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", 574 | "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", 575 | "dev": true 576 | }, 577 | "lru-cache": { 578 | "version": "4.1.5", 579 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", 580 | "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", 581 | "dev": true, 582 | "requires": { 583 | "pseudomap": "^1.0.2", 584 | "yallist": "^2.1.2" 585 | } 586 | }, 587 | "make-dir": { 588 | "version": "1.3.0", 589 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", 590 | "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", 591 | "dev": true, 592 | "requires": { 593 | "pify": "^3.0.0" 594 | } 595 | }, 596 | "minimatch": { 597 | "version": "3.0.4", 598 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 599 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 600 | "dev": true, 601 | "requires": { 602 | "brace-expansion": "^1.1.7" 603 | } 604 | }, 605 | "minimist": { 606 | "version": "1.2.5", 607 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 608 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 609 | "dev": true 610 | }, 611 | "mkdirp": { 612 | "version": "0.5.3", 613 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", 614 | "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", 615 | "dev": true, 616 | "requires": { 617 | "minimist": "^1.2.5" 618 | } 619 | }, 620 | "ms": { 621 | "version": "2.1.2", 622 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 623 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 624 | "dev": true 625 | }, 626 | "nodemon": { 627 | "version": "2.0.2", 628 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.2.tgz", 629 | "integrity": "sha512-GWhYPMfde2+M0FsHnggIHXTqPDHXia32HRhh6H0d75Mt9FKUoCBvumNHr7LdrpPBTKxsWmIEOjoN+P4IU6Hcaw==", 630 | "dev": true, 631 | "requires": { 632 | "chokidar": "^3.2.2", 633 | "debug": "^3.2.6", 634 | "ignore-by-default": "^1.0.1", 635 | "minimatch": "^3.0.4", 636 | "pstree.remy": "^1.1.7", 637 | "semver": "^5.7.1", 638 | "supports-color": "^5.5.0", 639 | "touch": "^3.1.0", 640 | "undefsafe": "^2.0.2", 641 | "update-notifier": "^2.5.0" 642 | } 643 | }, 644 | "nopt": { 645 | "version": "1.0.10", 646 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", 647 | "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", 648 | "dev": true, 649 | "requires": { 650 | "abbrev": "1" 651 | } 652 | }, 653 | "normalize-path": { 654 | "version": "3.0.0", 655 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 656 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 657 | "dev": true 658 | }, 659 | "npm-run-path": { 660 | "version": "2.0.2", 661 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", 662 | "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", 663 | "dev": true, 664 | "requires": { 665 | "path-key": "^2.0.0" 666 | } 667 | }, 668 | "once": { 669 | "version": "1.4.0", 670 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 671 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 672 | "dev": true, 673 | "requires": { 674 | "wrappy": "1" 675 | } 676 | }, 677 | "p-finally": { 678 | "version": "1.0.0", 679 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", 680 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", 681 | "dev": true 682 | }, 683 | "package-json": { 684 | "version": "4.0.1", 685 | "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", 686 | "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", 687 | "dev": true, 688 | "requires": { 689 | "got": "^6.7.1", 690 | "registry-auth-token": "^3.0.1", 691 | "registry-url": "^3.0.3", 692 | "semver": "^5.1.0" 693 | } 694 | }, 695 | "path-is-absolute": { 696 | "version": "1.0.1", 697 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 698 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 699 | "dev": true 700 | }, 701 | "path-is-inside": { 702 | "version": "1.0.2", 703 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 704 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", 705 | "dev": true 706 | }, 707 | "path-key": { 708 | "version": "2.0.1", 709 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 710 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 711 | "dev": true 712 | }, 713 | "path-parse": { 714 | "version": "1.0.7", 715 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 716 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 717 | "dev": true 718 | }, 719 | "picomatch": { 720 | "version": "2.2.2", 721 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", 722 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", 723 | "dev": true 724 | }, 725 | "pify": { 726 | "version": "3.0.0", 727 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", 728 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", 729 | "dev": true 730 | }, 731 | "prepend-http": { 732 | "version": "1.0.4", 733 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", 734 | "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", 735 | "dev": true 736 | }, 737 | "pseudomap": { 738 | "version": "1.0.2", 739 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 740 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", 741 | "dev": true 742 | }, 743 | "pstree.remy": { 744 | "version": "1.1.7", 745 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", 746 | "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", 747 | "dev": true 748 | }, 749 | "rc": { 750 | "version": "1.2.8", 751 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 752 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 753 | "dev": true, 754 | "requires": { 755 | "deep-extend": "^0.6.0", 756 | "ini": "~1.3.0", 757 | "minimist": "^1.2.0", 758 | "strip-json-comments": "~2.0.1" 759 | } 760 | }, 761 | "readdirp": { 762 | "version": "3.3.0", 763 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", 764 | "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", 765 | "dev": true, 766 | "requires": { 767 | "picomatch": "^2.0.7" 768 | } 769 | }, 770 | "registry-auth-token": { 771 | "version": "3.4.0", 772 | "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", 773 | "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", 774 | "dev": true, 775 | "requires": { 776 | "rc": "^1.1.6", 777 | "safe-buffer": "^5.0.1" 778 | } 779 | }, 780 | "registry-url": { 781 | "version": "3.1.0", 782 | "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", 783 | "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", 784 | "dev": true, 785 | "requires": { 786 | "rc": "^1.0.1" 787 | } 788 | }, 789 | "resolve": { 790 | "version": "1.13.1", 791 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", 792 | "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", 793 | "dev": true, 794 | "requires": { 795 | "path-parse": "^1.0.6" 796 | } 797 | }, 798 | "safe-buffer": { 799 | "version": "5.2.0", 800 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", 801 | "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", 802 | "dev": true 803 | }, 804 | "semver": { 805 | "version": "5.7.1", 806 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 807 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 808 | "dev": true 809 | }, 810 | "semver-diff": { 811 | "version": "2.1.0", 812 | "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", 813 | "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", 814 | "dev": true, 815 | "requires": { 816 | "semver": "^5.0.3" 817 | } 818 | }, 819 | "shebang-command": { 820 | "version": "1.2.0", 821 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 822 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 823 | "dev": true, 824 | "requires": { 825 | "shebang-regex": "^1.0.0" 826 | } 827 | }, 828 | "shebang-regex": { 829 | "version": "1.0.0", 830 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 831 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 832 | "dev": true 833 | }, 834 | "signal-exit": { 835 | "version": "3.0.2", 836 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 837 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 838 | "dev": true 839 | }, 840 | "sprintf-js": { 841 | "version": "1.0.3", 842 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 843 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 844 | "dev": true 845 | }, 846 | "string-width": { 847 | "version": "2.1.1", 848 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 849 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 850 | "dev": true, 851 | "requires": { 852 | "is-fullwidth-code-point": "^2.0.0", 853 | "strip-ansi": "^4.0.0" 854 | } 855 | }, 856 | "strip-ansi": { 857 | "version": "4.0.0", 858 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 859 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 860 | "dev": true, 861 | "requires": { 862 | "ansi-regex": "^3.0.0" 863 | } 864 | }, 865 | "strip-eof": { 866 | "version": "1.0.0", 867 | "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", 868 | "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", 869 | "dev": true 870 | }, 871 | "strip-json-comments": { 872 | "version": "2.0.1", 873 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 874 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 875 | "dev": true 876 | }, 877 | "supports-color": { 878 | "version": "5.5.0", 879 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 880 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 881 | "dev": true, 882 | "requires": { 883 | "has-flag": "^3.0.0" 884 | } 885 | }, 886 | "term-size": { 887 | "version": "1.2.0", 888 | "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", 889 | "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", 890 | "dev": true, 891 | "requires": { 892 | "execa": "^0.7.0" 893 | } 894 | }, 895 | "timed-out": { 896 | "version": "4.0.1", 897 | "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", 898 | "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", 899 | "dev": true 900 | }, 901 | "to-regex-range": { 902 | "version": "5.0.1", 903 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 904 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 905 | "dev": true, 906 | "requires": { 907 | "is-number": "^7.0.0" 908 | } 909 | }, 910 | "touch": { 911 | "version": "3.1.0", 912 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", 913 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", 914 | "dev": true, 915 | "requires": { 916 | "nopt": "~1.0.10" 917 | } 918 | }, 919 | "tslib": { 920 | "version": "1.10.0", 921 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", 922 | "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", 923 | "dev": true 924 | }, 925 | "tslint": { 926 | "version": "5.20.1", 927 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", 928 | "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", 929 | "dev": true, 930 | "requires": { 931 | "@babel/code-frame": "^7.0.0", 932 | "builtin-modules": "^1.1.1", 933 | "chalk": "^2.3.0", 934 | "commander": "^2.12.1", 935 | "diff": "^4.0.1", 936 | "glob": "^7.1.1", 937 | "js-yaml": "^3.13.1", 938 | "minimatch": "^3.0.4", 939 | "mkdirp": "^0.5.1", 940 | "resolve": "^1.3.2", 941 | "semver": "^5.3.0", 942 | "tslib": "^1.8.0", 943 | "tsutils": "^2.29.0" 944 | } 945 | }, 946 | "tsutils": { 947 | "version": "2.29.0", 948 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 949 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 950 | "dev": true, 951 | "requires": { 952 | "tslib": "^1.8.1" 953 | } 954 | }, 955 | "typescript": { 956 | "version": "3.8.3", 957 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", 958 | "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", 959 | "dev": true 960 | }, 961 | "undefsafe": { 962 | "version": "2.0.3", 963 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", 964 | "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", 965 | "dev": true, 966 | "requires": { 967 | "debug": "^2.2.0" 968 | }, 969 | "dependencies": { 970 | "debug": { 971 | "version": "2.6.9", 972 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 973 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 974 | "dev": true, 975 | "requires": { 976 | "ms": "2.0.0" 977 | } 978 | }, 979 | "ms": { 980 | "version": "2.0.0", 981 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 982 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 983 | "dev": true 984 | } 985 | } 986 | }, 987 | "unique-string": { 988 | "version": "1.0.0", 989 | "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", 990 | "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", 991 | "dev": true, 992 | "requires": { 993 | "crypto-random-string": "^1.0.0" 994 | } 995 | }, 996 | "unzip-response": { 997 | "version": "2.0.1", 998 | "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", 999 | "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", 1000 | "dev": true 1001 | }, 1002 | "update-notifier": { 1003 | "version": "2.5.0", 1004 | "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", 1005 | "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", 1006 | "dev": true, 1007 | "requires": { 1008 | "boxen": "^1.2.1", 1009 | "chalk": "^2.0.1", 1010 | "configstore": "^3.0.0", 1011 | "import-lazy": "^2.1.0", 1012 | "is-ci": "^1.0.10", 1013 | "is-installed-globally": "^0.1.0", 1014 | "is-npm": "^1.0.0", 1015 | "latest-version": "^3.0.0", 1016 | "semver-diff": "^2.0.0", 1017 | "xdg-basedir": "^3.0.0" 1018 | } 1019 | }, 1020 | "url-parse-lax": { 1021 | "version": "1.0.0", 1022 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", 1023 | "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", 1024 | "dev": true, 1025 | "requires": { 1026 | "prepend-http": "^1.0.1" 1027 | } 1028 | }, 1029 | "which": { 1030 | "version": "1.3.1", 1031 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1032 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1033 | "dev": true, 1034 | "requires": { 1035 | "isexe": "^2.0.0" 1036 | } 1037 | }, 1038 | "widest-line": { 1039 | "version": "2.0.1", 1040 | "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", 1041 | "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", 1042 | "dev": true, 1043 | "requires": { 1044 | "string-width": "^2.1.1" 1045 | } 1046 | }, 1047 | "wrappy": { 1048 | "version": "1.0.2", 1049 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1050 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1051 | "dev": true 1052 | }, 1053 | "write-file-atomic": { 1054 | "version": "2.4.3", 1055 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", 1056 | "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", 1057 | "dev": true, 1058 | "requires": { 1059 | "graceful-fs": "^4.1.11", 1060 | "imurmurhash": "^0.1.4", 1061 | "signal-exit": "^3.0.2" 1062 | } 1063 | }, 1064 | "xdg-basedir": { 1065 | "version": "3.0.0", 1066 | "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", 1067 | "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", 1068 | "dev": true 1069 | }, 1070 | "yallist": { 1071 | "version": "2.1.2", 1072 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 1073 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", 1074 | "dev": true 1075 | } 1076 | } 1077 | } 1078 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "data-structures-and-algorithms-in-javascript", 3 | "version": "1.0.0", 4 | "description": "the implementation of basic data structure and algorithm in JavaScript", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "NODE_ENV=development nodemon ./index.js", 9 | "watch": "tsc --watch", 10 | "build": "rm -rf ./dist && tsc" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/ovenzeze/data-structures-and-algorithms-in-javascript.git" 15 | }, 16 | "devDependencies": { 17 | "nodemon": "^2.0.2", 18 | "tslint": "^5.12.0", 19 | "typescript": "^3.8.3" 20 | }, 21 | "author": "isake", 22 | "license": "ISC", 23 | "bugs": { 24 | "url": "https://github.com/ovenzeze/data-structures-and-algorithms-in-javascript/issues" 25 | }, 26 | "homepage": "https://github.com/ovenzeze/data-structures-and-algorithms-in-javascript#readme" 27 | } 28 | -------------------------------------------------------------------------------- /src/base/binary-search.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * search index of target from a sorted no-duplicate array list 3 | * @param list: number[] 4 | * @param target: number 5 | * @returns index: number 6 | */ 7 | const BinarySearch = (list: number[], target: number) => { 8 | let index: number = -1 9 | let left: number = 0 10 | let right: number = list.length - 1 11 | let mid: number 12 | if (list.length === 0) { 13 | return index 14 | } 15 | while (left <= right) { 16 | console.log('[debug][left]:', left, '[debug][mid]:', mid, '[debug][right]:', right) 17 | mid = Math.floor(left + (right - left) / 2) 18 | if (list[mid] > target) { 19 | right = mid - 1 20 | } else if (list[mid] < target) { 21 | left = mid + 1 22 | } else { 23 | index = mid 24 | break 25 | } 26 | } 27 | return index 28 | } 29 | const BinarySearchRecur = (list: number[], target: number, left?: number, right?: number) => { 30 | left = left || 0 31 | right = right || list.length - 1 32 | let mid: number 33 | mid = Math.floor(left + (right - left) / 2) 34 | if (left === right && list[left] !== target) { 35 | return -1 36 | } 37 | if (list[mid] > target) { 38 | return BinarySearchRecur(list, target, left, mid - 1) 39 | } else if (list[mid] < target) { 40 | return BinarySearchRecur(list, target, mid + 1, right) 41 | } else { 42 | return mid 43 | } 44 | } 45 | /** 46 | * search first index of target from a sorted array list, may contains duplicate element 47 | * @param list: number[] 48 | * @param target: number 49 | * @returns list: number[] 50 | */ 51 | const BinarySearchWithDupList = (list: number[], target: number) => { 52 | let index: number = -1 53 | let left: number = 0 54 | let right: number = list.length - 1 55 | let mid: number 56 | while (left <= right) { 57 | mid = Math.floor(left + (right - left) / 2) 58 | console.log('[debug][left]:', left, '[debug][mid]:', mid, '[debug][right]:', right) 59 | if (list[mid] >= target) { 60 | right = mid - 1 61 | } else if (list[mid] < target) { 62 | left = mid + 1 63 | } 64 | } 65 | index = list[left] === target ? left : index 66 | return index 67 | } 68 | const BinarySearchWithDupListRecur = (list: number[], target: number, left?: number, right?: number) => { 69 | let index: number = -1 70 | left = left || 0 71 | right = right === 0 ? right : (right || list.length - 1) 72 | let mid: number 73 | if (left <= right) { 74 | mid = Math.floor(left + (right - left) / 2) 75 | console.log('[debug][left]:', left, '[debug][mid]:', mid, '[debug][right]:', right) 76 | if (list[mid] >= target) { 77 | return BinarySearchWithDupListRecur(list, target, left, mid - 1) 78 | } else if (list[mid] < target) { 79 | return BinarySearchWithDupListRecur(list, target, mid + 1, right) 80 | } 81 | } 82 | index = list[left] === target ? left : index 83 | return index 84 | } 85 | /** 86 | * search for all indexes of the target value from an ascending array that may contain duplicate elements 87 | * @param list: number[] 88 | * @param target: number 89 | * @returns list: number[] all index of target 90 | */ 91 | const BinarySearchAllIndex = (list: number[], target: number) => { 92 | const indexList: number[] = [] 93 | const firstIndex: number = BinarySearchFirstDupElement(list, target) 94 | const lastIndex: number = BinarySearchLastDupElement(list, target) 95 | console.log('firstIndex:', firstIndex, 'lastIndex:', lastIndex) 96 | if (firstIndex === lastIndex && firstIndex !== -1) { 97 | indexList.push(firstIndex) 98 | } else if (firstIndex !== lastIndex) { 99 | for (let i = firstIndex; i <= lastIndex; i++) { 100 | indexList.push(i) 101 | } 102 | } 103 | return indexList 104 | } 105 | const BinarySearchFirstDupElement = (list: number[], target: number) => { 106 | let index: number = -1 107 | let left: number = 0 108 | let right: number = list.length - 1 109 | let mid: number 110 | while (left <= right) { 111 | mid = Math.floor(left + (right - left) / 2) 112 | console.log('[debug][left]:', left, '[debug][mid]:', mid, '[debug][right]:', right) 113 | if (list[mid] >= target) { 114 | right = mid - 1 115 | } else if (list[mid] < target) { 116 | left = mid + 1 117 | } 118 | } 119 | // Q: why use left index to check? 120 | index = list[left] === target ? left : index 121 | return index 122 | } 123 | const BinarySearchLastDupElement = (list: number[], target: number) => { 124 | let index: number = -1 125 | let left: number = 0 126 | let right: number = list.length - 1 127 | let mid: number 128 | while (left <= right) { 129 | mid = Math.floor(left + (right - left) / 2) 130 | console.log('[debug][left]:', left, '[debug][mid]:', mid, '[debug][right]:', right) 131 | if (list[mid] > target) { 132 | right = mid - 1 133 | } else if (list[mid] <= target) { 134 | left = mid + 1 135 | } 136 | } 137 | // Q: why use right index to check? 138 | index = list[right] === target ? right : index 139 | return index 140 | } 141 | // ============================================>Export 142 | export { BinarySearch, BinarySearchRecur, BinarySearchWithDupList, BinarySearchWithDupListRecur, BinarySearchAllIndex } 143 | -------------------------------------------------------------------------------- /src/base/linked-list.ts: -------------------------------------------------------------------------------- 1 | class LinkedListNode { 2 | public next: any 3 | private element: any 4 | 5 | constructor(element: any) { 6 | this.element = element 7 | this.next = null 8 | } 9 | } 10 | 11 | class LinkedList { 12 | private head: any 13 | 14 | constructor() { 15 | this.head = new LinkedListNode('head') 16 | } 17 | 18 | public insert(insertElement: any, element: any) { 19 | const opNode = this.find(element) 20 | const insertNode = new LinkedListNode(insertElement) 21 | insertNode.next = opNode.next 22 | opNode.element = insertElement 23 | opNode.next = insertNode 24 | } 25 | 26 | public delete(deleteElement: any) { 27 | const opNode = this.findPrev(deleteElement) 28 | opNode.next = opNode.next.next 29 | } 30 | 31 | public display() { 32 | let curNode = this.head 33 | let nodeNum = 0 34 | const elementArr = [] 35 | while (curNode.next !== null) { 36 | elementArr.push(curNode.element) 37 | nodeNum++ 38 | curNode = curNode.next 39 | } 40 | console.log('[linkList][length]:', nodeNum) 41 | console.log('[linkList][detail]:', elementArr) 42 | } 43 | 44 | private find(element: any) { 45 | let curNode = this.head 46 | let curElement = curNode.element 47 | while (curElement !== element) { 48 | curNode = curNode.next 49 | curElement = curNode.element 50 | } 51 | return curNode 52 | } 53 | 54 | private findPrev(element: any) { 55 | let curNode = this.head 56 | let nextElement = curNode.next.element 57 | while (nextElement !== element) { 58 | curNode = curNode.next 59 | nextElement = curNode.next.element 60 | } 61 | return curNode 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/base/queue.ts: -------------------------------------------------------------------------------- 1 | class Queue { 2 | private dataSource: any 3 | 4 | constructor(origin: any) { 5 | if (origin instanceof Array) { 6 | this.dataSource = origin || [] 7 | } 8 | } 9 | 10 | public enqueue(item: any) { 11 | this.dataSource.push(item) 12 | } 13 | 14 | public dequeue() { 15 | this.dataSource.shift() 16 | } 17 | 18 | public front() { 19 | return this.dataSource[0] 20 | } 21 | 22 | public back() { 23 | return this.dataSource[this.dataSource.length - 1] 24 | } 25 | 26 | public display() { 27 | return this.dataSource 28 | } 29 | 30 | public isEmpty() { 31 | const isEmpty = this.dataSource.length ? false : true 32 | return isEmpty 33 | } 34 | } 35 | 36 | // =============================>>>>Export 37 | export { 38 | Queue 39 | } 40 | -------------------------------------------------------------------------------- /src/base/stack.ts: -------------------------------------------------------------------------------- 1 | class Stack { 2 | private dataSource: any 3 | private top: number 4 | 5 | constructor(origin: any) { 6 | if (origin instanceof Array) { 7 | this.dataSource = origin || [] 8 | this.top = origin.length || 0 9 | } 10 | } 11 | 12 | public push(item: any) { 13 | this.dataSource[this.top++] = item 14 | } 15 | 16 | public pop() { 17 | if (this.top !== 0) { 18 | return this.dataSource[--this.top] 19 | } 20 | } 21 | 22 | public peek() { 23 | return this.dataSource[this.top - 1] 24 | } 25 | 26 | public length() { 27 | return this.top 28 | } 29 | 30 | public clear() { 31 | this.top = 0 32 | } 33 | } 34 | 35 | // =============================>>>>Export 36 | export { 37 | Stack 38 | } 39 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Stack } from './base/stack' 2 | import { Queue } from './base/queue' 3 | import { BinarySearch, BinarySearchRecur, BinarySearchWithDupList, BinarySearchWithDupListRecur, BinarySearchAllIndex } from './base/binary-search' 4 | 5 | // =============================>>>>Suits 6 | 7 | // =============================>>>>Stack 8 | const stack = new Stack(['one', 'two', 'three']) 9 | stack.push('four') 10 | stack.pop() 11 | stack.peek() 12 | console.log('[info][stack][peek]:', stack.peek()) 13 | console.log('[info][stack][length]:', stack.length()) 14 | stack.clear() 15 | console.log('[info][stack][peek]:', stack.peek()) 16 | 17 | // =============================>>>>Queue 18 | const queue = new Queue(['one', 'two', 'three', 'four']) 19 | queue.enqueue('five') 20 | console.log('[info][queue]:', queue.display()) 21 | queue.dequeue() 22 | console.log('[info][queue]:', queue.display()) 23 | console.log('[info][queue][front]:', queue.front()) 24 | console.log('[info][queue][back]:', queue.back()) 25 | // =============================>>>>BinarySearch 26 | const list = [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12] 27 | const target = 11 28 | const binarySearchRes = BinarySearch(list, target) 29 | console.log('[info][BinarySearch][list]:', list) 30 | console.log('[info][BinarySearch][target]:', target) 31 | console.log('[info][BinarySearch][result]:', binarySearchRes) 32 | // =============================>>>>BinarySearchWithDupList 33 | const list2 = [1, 2, 3, 3, 3, 3, 5] 34 | const target2 = 3 35 | const binarySearchWithDupListRes = BinarySearchWithDupList(list2, target2) 36 | console.log('[info][BinarySearchWithDupList][list]:', list2) 37 | console.log('[info][BinarySearchWithDupList][target]:', target2) 38 | console.log('[info][BinarySearchWithDupList][result]:', binarySearchWithDupListRes) 39 | // =============================>>>>BinarySearchRecur 40 | const list3 = [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12] 41 | const target3 = 20 42 | const BinarySearchRecurRes = BinarySearchRecur(list3, target3) 43 | console.log('[info][BinarySearchRecur][list]:', list3) 44 | console.log('[info][BinarySearchRecur][target]:', target3) 45 | console.log('[info][BinarySearchRecur][result]:', BinarySearchRecurRes) 46 | // =============================>>>>BinarySearchWithDupListRecur 47 | const list4 = [1, 2, 2, 3, 4, 5, 6, 7] 48 | const target4 = 3 49 | const binarySearchWithDupListRecurRes = BinarySearchWithDupListRecur(list4, target4) 50 | console.log('[info][BinarySearchWithDupListRecur][list]:', list4) 51 | console.log('[info][BinarySearchWithDupListRecur][target]:', target4) 52 | console.log('[info][BinarySearchWithDupListRecur][result]:', binarySearchWithDupListRecurRes) 53 | // =============================>>>>BinarySearchAllIndex 54 | const list5 = [1, 2, 2, 2, 3, 4, 5, 6, 7] 55 | const target5 = 2 56 | const BinarySearchAllIndexRes = BinarySearchAllIndex(list5, target5) 57 | console.log('[info][BinarySearchAllIndex][list]:', list5) 58 | console.log('[info][BinarySearchAllIndex][target]:', target5) 59 | console.log('[info][BinarySearchAllIndex][result]:', BinarySearchAllIndexRes) 60 | -------------------------------------------------------------------------------- /src/js/bin-search.js: -------------------------------------------------------------------------------- 1 | // 二分查找 2 | // 从一个从小到大排列的有序数组中找出指定值的位置 3 | function binSearch(arr, data) { 4 | let len = arr.length - 1, 5 | startPivot = 0, 6 | mid; 7 | while (startPivot <= len) { 8 | mid = Math.floor((len + startPivot) / 2); 9 | if (arr[mid] < data) { 10 | startPivot = mid + 1; 11 | } else if (arr[mid] > data) { 12 | len = mid - 1; 13 | } else { 14 | return mid; 15 | } 16 | } 17 | return -1; 18 | } 19 | 20 | let arr = [1, 3, 5, 7, 10, 13, 24, 35, 38, 40, 44, 56, 66, 77, 88, 99, 123]; 21 | console.log(binSearch(arr, 24)); -------------------------------------------------------------------------------- /src/js/binary-tree.js: -------------------------------------------------------------------------------- 1 | // 树是一种非线性的数据结构,以分层的方式存储数据。树通常用于存储具有层级关系的数据,比如文件系统中的文件。 2 | // 二叉树和二叉查找树,二叉树每个节点的子节点不允许超过两个。二叉查找树是一种特殊的二叉树,相对较小的值保存在做节点,较大的值保存在右节点。 3 | 4 | // 二叉树 5 | function Node(data,left,right) { 6 | this.data = data; 7 | this.left = left; 8 | this.right = right; 9 | this.show = show; 10 | } 11 | 12 | function show () { 13 | return this.data; 14 | } 15 | 16 | // 二叉查找树(BST) 17 | function BST() { 18 | this.root = null; 19 | this.insert = insert;//插入节点 20 | this.inOrder = inOrder;//中序遍历 21 | this.preOrder = preOrder;//先序遍历 22 | this.postOrder = postOrder;//后序遍历 23 | this.getMax = getMax; 24 | this.getMin = getMin; 25 | this.find = find; 26 | }; 27 | 28 | function insert(data) { 29 | //创建一个Node将数据传入 30 | // 检查BST是否有根节点,如果没有此节点设置为根节点,插入结束 31 | // 如果不是根节点,则遍历BST,找到插入的适当位置。 32 | // 查找正确插入点的算法: 33 | // 1:设根节点为当前节点; 34 | // 2:如果待插入节点保存的数据小于当前节点,则设新的当前节点为原节点的左节点,反之,执行第四步。 35 | // 3:如果当前节点的左节点为null,就将新节点插入这个位置,退出循环;反之,继续执行下一次循环; 36 | // 4:设新的当前节点为原节点的右节点; 37 | // 5:如果当前节点的右节点为null,就将新的节点插入这个位置,退出循环;反之,继续执行下一次循环。 38 | let n = new Node(data,null,null); 39 | if(this.root == null) { 40 | this.root = n; 41 | }else { 42 | let current = this.root; 43 | let parent; 44 | while(true) { 45 | parent = current; 46 | if(data < current.data) { 47 | current = current.left; 48 | if(current == null) { 49 | parent.left = n; 50 | break; 51 | } 52 | } 53 | else { 54 | current = current.right; 55 | if(current == null) { 56 | parent.right = n; 57 | break; 58 | } 59 | } 60 | } 61 | } 62 | }; 63 | 64 | // 中序遍历 65 | // 按照节点上的键值,以升序的方式访问BST上的所有节点 66 | // 先访问左子树,再访问根节点,最后访问右子树 67 | function inOrder (node) { 68 | if(!(node == null)) { 69 | inOrder(node.left); 70 | console.log(node.show()); 71 | inOrder(node.right); 72 | } 73 | }; 74 | // 先序遍历 75 | // 先访问根节点,然后以同样的方式访问左子树和右子树 76 | function preOrder (node) { 77 | if(!(node == null)) { 78 | console.log(node.show()); 79 | preOrder(node.left); 80 | preOrder(node.right); 81 | } 82 | }; 83 | // 后序遍历 84 | // 先访问叶子节点,从左子树到右子树,再到根节点 85 | function postOrder(node) { 86 | if(!(node == null)) { 87 | postOrder(node.left); 88 | postOrder(node.right); 89 | console.log(node.show()); 90 | } 91 | }; 92 | 93 | // 查找二叉树最大值 94 | function getMax() { 95 | let currentNode = this.root; 96 | while(!(currentNode.right == null)) { 97 | currentNode = currentNode.right; 98 | } 99 | return currentNode.data; 100 | }; 101 | 102 | // 查找二叉树最小值 103 | function getMin() { 104 | let currentNode = this.root; 105 | while(!(currentNode.left == null)) { 106 | currentNode = currentNode.left; 107 | } 108 | return currentNode.data; 109 | }; 110 | 111 | // 在二叉搜索树查找给定值 112 | function find(data) { 113 | let current = this.root; 114 | while(current != null) { 115 | if(current.data == data) { 116 | return current; 117 | }else if(data < current.data){ 118 | current = current.left; 119 | }else { 120 | current = current.right; 121 | } 122 | } 123 | return null; 124 | }; 125 | let nums = new BST(); 126 | nums.insert(23); 127 | nums.insert(16); 128 | nums.insert(3); 129 | nums.insert(22); 130 | nums.insert(21); 131 | nums.insert(22); 132 | nums.insert(45); 133 | nums.insert(37); 134 | // nums.insert(99); 135 | console.log("中序遍历"); 136 | inOrder(nums.root); 137 | console.log("先序遍历"); 138 | preOrder(nums.root); 139 | console.log("后序遍历"); 140 | postOrder(nums.root); 141 | console.log(`最小值为:${nums.getMin()}`); 142 | console.log(`最大值为:${nums.getMax()}`); 143 | console.log(`指定值所在的节点为:${nums.find(3)}`); 144 | -------------------------------------------------------------------------------- /src/js/check-binary-tree-is-BST.js: -------------------------------------------------------------------------------- 1 | // BST is a type of binary tree with following properties: 2 | // • The left subtree of a node contains only nodes with keys less than the node’s key. 3 | // • The right subtree of a node contains only nodes with keys greater than the node’s key. 4 | // • Both the left and right subtrees must also be binary search trees. 5 | function Node(data, left, right) { 6 | this.data = data; 7 | this.left = left; 8 | this.right = right; 9 | // this.show = show; 10 | } 11 | 12 | function binaryTree() { 13 | this.root = null; 14 | this.isBST = isBST; 15 | } 16 | // check a binary tree is BST,return true or false 17 | function isBST() { 18 | return isBSTUtil(this.root, Number.MIN_VALUE, Number.MAX_VALUE); 19 | } 20 | // return true if the given tree is BST and its data <= the max value of Sub-tree also >= min value of Sub-tree 21 | function isBSTUtil(node, min, max) { 22 | // empty tree is BST 23 | if (!node) { 24 | return true; 25 | } 26 | // node data should >= min value also <= max value 27 | if (node.data < min || node.data > max) { 28 | return false; 29 | } 30 | // if not returned, check the subtrees recursively 31 | return isBSTUtil(node.left, min, node.data - 1) && isBSTUtil(node.right, node.data + 1, max); 32 | } 33 | 34 | // test 35 | let BSTree = new binaryTree(); 36 | BSTree.root = new Node(4, null, null); 37 | BSTree.root.left = new Node(2, null, null); 38 | BSTree.root.right = new Node(5, null, null); 39 | BSTree.root.left.left = new Node(1, null, null); 40 | BSTree.root.left.right = new Node(3, null, null); 41 | let notBSTree = new binaryTree(); 42 | notBSTree.root = new Node(5, null, null); 43 | notBSTree.root.left = new Node(4, null, null); 44 | notBSTree.root.right = new Node(2, null, null); 45 | notBSTree.root.right.left = new Node(1, null, null); 46 | notBSTree.root.right.right = new Node(3, null, null); 47 | console.log(BSTree.isBST()); //test BST 48 | console.log(notBSTree.isBST()); // test false BST -------------------------------------------------------------------------------- /src/js/doubly-linked-circual-list.js: -------------------------------------------------------------------------------- 1 | // doubly circual linkedList 2 | // the only difference with doubly linkedList is the next pointer of the last Node point to the first node ,and the previous pointer of the first Node point to the last Node 3 | function Node(element) { 4 | this.element = element; 5 | this.next = null; 6 | this.previous = null; 7 | } 8 | function linkedList() { 9 | this.head = new Node("head"); 10 | this.head.next = this.head; 11 | this.head.previous = this.head; 12 | // four methods: find insert remove display 13 | this.find = find; 14 | this.insert = insert; 15 | this.remove = remove; 16 | this.display = display; 17 | } 18 | 19 | function find(item) { 20 | let currNode = this.head; 21 | // exit the loop:find the Node contain given item or find the last Node 22 | while(currNode.element != item && currNode.next.element != "head") { 23 | currNode = currNode.next; 24 | } 25 | if(currNode.element == item) { 26 | return currNode; 27 | } 28 | return -1; 29 | } 30 | 31 | // insert element after the given item,return true or false 32 | function insert(insertElement,item) { 33 | let newNode = new Node(insertElement); 34 | let insertPos = this.find(item); 35 | if(insertPos == -1) { 36 | return false; 37 | } 38 | else if(insertPos.element == "head"){ 39 | insertPos.next = newNode; 40 | insertPos.previous = newNode; 41 | newNode.next = insertPos; 42 | newNode.previous = insertPos; 43 | return true; 44 | } 45 | else if(insertPos.next.element == "head" && insertPos.element != "head") { 46 | insertPos.next = newNode; 47 | newNode.next = this.head; 48 | newNode.previous = insertPos; 49 | return true; 50 | } 51 | else { 52 | newNode.next = insertPos.next; 53 | insertPos.next = newNode; 54 | newNode.previous = insertPos; 55 | return true; 56 | } 57 | } 58 | 59 | // remove the Node contain given item,return true or false 60 | function remove(item) { 61 | let removePos = this.find(item); 62 | if(removePos == -1) { 63 | return false; 64 | }else { 65 | removePos.previous.next = removePos.next; 66 | return true; 67 | } 68 | } 69 | 70 | //display all element 71 | function display() { 72 | let currNode = this.head; 73 | while(currNode != null && currNode.next.element != "head") { 74 | console.log(currNode.next.element); 75 | currNode = currNode.next; 76 | } 77 | } 78 | 79 | // test 80 | let linkedListTest = new linkedList(); 81 | linkedListTest.insert("oven", "head"); 82 | linkedListTest.insert("ovenzeze", "oven"); 83 | linkedListTest.insert("ovenerly", "ovenzeze"); 84 | linkedListTest.insert("chanzen", "ovenerly"); 85 | linkedListTest.insert("chanzen.zhang", "chanzen"); 86 | linkedListTest.display(); 87 | linkedListTest.remove("chanzen.zhang"); 88 | console.log("after remove [chanzen.zhang]"); 89 | linkedListTest.display(); 90 | -------------------------------------------------------------------------------- /src/js/doubly-linked-list.js: -------------------------------------------------------------------------------- 1 | // 双向链表,每一个节点不仅保存指向下一个节点的链接还保存着指向前一个节点的链接 2 | function Node (element) { 3 | this.element = element; 4 | this.next = null; 5 | this.previous = null; 6 | } 7 | function dbLinkedList () { 8 | this.head = new Node("head"); 9 | this.find = find; 10 | this.insert = insert; 11 | this.display = display; 12 | this.dispReverse = dispReverse; 13 | this.findLast = findLast; 14 | this.remove = remove; 15 | 16 | // 根据传入的数据返回对应的节点 17 | function find(item) { 18 | let currNode = this.head; 19 | while(currNode.element != item) { 20 | currNode = currNode.next; 21 | } 22 | return currNode; 23 | } 24 | // 根据要插入的元素和要被插入的位置的前一个元素进行插入操作 25 | function insert(insertElement,item) { 26 | let newNode = new Node(insertElement); 27 | let currNode = this.find(item); 28 | newNode.next = currNode.next; 29 | newNode.previous = currNode; 30 | // currNode.next.previous = newNode; 31 | currNode.next = newNode; 32 | } 33 | // 查找链表的最后一个节点 34 | function findLast() { 35 | let currNode = this.head; 36 | while(currNode.next != null) { 37 | currNode = currNode.next; 38 | } 39 | return currNode; 40 | } 41 | // 按顺序显示链表中的元素 42 | function display() { 43 | let currNode = this.head; 44 | while(currNode.next != null) { 45 | console.log(currNode.next.element); 46 | currNode = currNode.next; 47 | } 48 | } 49 | // 倒序显示链表中的元素 50 | function dispReverse() { 51 | let currNode = this.findLast(); 52 | while(currNode.previous != null) { 53 | console.log(currNode.element); 54 | currNode = currNode.previous; 55 | } 56 | } 57 | // 根据传入的元素删除对应的节点 58 | function remove(item) { 59 | let currNode = this.find(item); 60 | if(currNode.next == null){ 61 | currNode.previous.next = currNode.next; 62 | }else { 63 | currNode.previous.next = currNode.next; 64 | currNode.next.previous = currNode.previous; 65 | currNode.next = null; 66 | currNode.previous = null; 67 | } 68 | } 69 | 70 | } 71 | 72 | // test 73 | let dbLinkedListTest = new dbLinkedList(); 74 | dbLinkedListTest.insert("oven", "head"); 75 | dbLinkedListTest.insert("ovenzeze", "oven"); 76 | dbLinkedListTest.insert("ovenerly", "ovenzeze"); 77 | dbLinkedListTest.insert("chanzen", "ovenerly"); 78 | dbLinkedListTest.insert("chanzen.zhang", "chanzen"); 79 | dbLinkedListTest.display(); 80 | console.log("reverse display----------------"); 81 | dbLinkedListTest.dispReverse(); 82 | dbLinkedListTest.remove("chanzen"); 83 | console.log("after remove [chanzen]"); 84 | dbLinkedListTest.dispReverse(); 85 | -------------------------------------------------------------------------------- /src/js/has-loop-in-linked-list.js: -------------------------------------------------------------------------------- 1 | // whether the doubly linked list has a loop 2 | function Node(element) { 3 | this.element = element; 4 | this.next = null; 5 | } 6 | 7 | function linkedList() { 8 | this.head = new Node("head"); 9 | this.head.next = this.head; 10 | this.detectLoop = detectLoop; 11 | } 12 | 13 | // use two pointer (fast and slow), traversal the linkedList if meet, indicate there exit a loop 14 | function detectLoop() { 15 | let slow = this.head, 16 | fast = this.head; 17 | while (slow != null && fast != null && fast.next != null) { 18 | slow = slow.next; 19 | fast = fast.next.next; 20 | if (slow === fast) { 21 | return true; 22 | } 23 | } 24 | return false; 25 | } 26 | // test 27 | let cycleList = new linkedList(); 28 | cycleList.head.next = new Node("oven"); 29 | cycleList.head.next.next = new Node("ovenzeze"); 30 | cycleList.head.next.next.next = new Node("ovenzhang"); 31 | cycleList.head.next.next.next.next = new Node("chanzen"); 32 | cycleList.head.next.next.next.next.next = cycleList.head.next.next; 33 | console.log(cycleList.detectLoop()); -------------------------------------------------------------------------------- /src/js/linked-list.js: -------------------------------------------------------------------------------- 1 | // 链表的节点 2 | function Node(element) { 3 | this.element = element; 4 | this.next = null; 5 | } 6 | // 链表类,提供操作链表的一些方法 7 | function linkList() { 8 | this.head = new Node("head"); 9 | this.find = find; //查找给定值 10 | this.insert = insert; //在链表插入给定值 11 | this.remove = remove;//在链表移除给定值 12 | this.display = display; //显示给定值 13 | this.findPrevious = findPrevious; 14 | 15 | function find(element) { 16 | let currNode = this.head; 17 | while (currNode.element != element) { 18 | currNode = currNode.next; 19 | } 20 | return currNode; 21 | } 22 | 23 | // 需要给出在那个元素之后插入元素 24 | function insert(insertElement, item) { 25 | let newNode = new Node(insertElement); 26 | let currNode = this.find(item); 27 | newNode.next = currNode.next; 28 | currNode.next = newNode; 29 | } 30 | 31 | // 显示链表中所有元素 32 | function display() { 33 | let currNode = this.head; 34 | while (currNode.next != null) { 35 | console.log(currNode.next.element); 36 | currNode = currNode.next; 37 | } 38 | } 39 | 40 | function findPrevious(item) { 41 | let currNode = this.head; 42 | while (currNode.next != null && currNode.next.element != item) { 43 | currNode = currNode.next; 44 | } 45 | return currNode; 46 | } 47 | function remove(item) { 48 | let prevNode = this.findPrevious(item); 49 | if (prevNode.next != null) { 50 | prevNode.next = prevNode.next.next; 51 | } 52 | } 53 | 54 | } 55 | 56 | // test 57 | let linkedListTest = new linkList(); 58 | linkedListTest.insert("oven", "head"); 59 | linkedListTest.insert("ovenzeze", "oven"); 60 | linkedListTest.insert("ovenerly", "ovenzeze"); 61 | linkedListTest.insert("chanzen", "ovenerly"); 62 | linkedListTest.insert("chanzen.zhang", "chanzen"); 63 | linkedListTest.display(); 64 | linkedListTest.remove("chanzen.zhang"); 65 | console.log("after remove [chanzen.zhang]"); 66 | linkedListTest.display(); 67 | -------------------------------------------------------------------------------- /src/js/list.js: -------------------------------------------------------------------------------- 1 | // 数据结构描述:列表是一组有序的数据,每个列表中的数据项称之为元素。在JavaScript中,列表中的元素可以是任意数据类型 2 | // 不包含任意元素的列表称为空列表,包含元素的个数称为列表的length,可以在列表末尾append一个元素,在给定发的元素后或起止位置insert一个元素,使用remove方法从列表中删除元素,使用clear方法清空列表中所有元素。 3 | function list() { 4 | this.listSize = 0; 5 | this.pos = 0; 6 | this.length = length; 7 | this.toString = toString; 8 | this.find = find;//查找列表中指定元素 9 | this.remove = remove;//在列表中移除指定元素 10 | this.append = append;//在列表末尾添加新元素 11 | this.currPos = currPos;//返回列表当前位置 12 | this.dataStore = [];//使用数组来模拟 13 | this.clear = clear;//清空列表 14 | this.insert = insert;//在列表指定位置插入元素 15 | this.front = front;//移动当前位置到列表第一个元素 16 | this.end = end;//移动当前位置到列表最后一项 17 | this.prev = prev;//将当前位置前移一位 18 | this.next = next;//将当前位置前移一位 19 | this.moveTo = moveTo;//将当前位置移动到指定位置 20 | this.getElement = getElement;//返回当前位置的元素 21 | this.contains = contains;//判断给定值是否在列表中 22 | 23 | function append (element) { 24 | this.dataStore[this.listSize++] = element; 25 | }; 26 | 27 | function find (element) { 28 | let elementPos; 29 | this.dataStore.forEach( (value,index,array) => { 30 | if(element == value) { 31 | elementPos = index; 32 | } 33 | }) 34 | return elementPos; 35 | }; 36 | 37 | function remove (element) { 38 | let elementIndex = this.find(element); 39 | if(elementIndex != -1) { 40 | this.dataStore.splice(elementIndex,1); 41 | --this.listSize; 42 | return true; 43 | } 44 | return false; 45 | }; 46 | 47 | function length () { 48 | return this.listSize; 49 | }; 50 | 51 | function toString () { 52 | return this.dataStore; 53 | }; 54 | 55 | function currPos () { 56 | return this.pos; 57 | }; 58 | 59 | function clear () { 60 | delete this.dataStore; 61 | this.dataStore.length = 0; 62 | this.listSize = this.pos = 0; 63 | }; 64 | 65 | function insert (element,beforeElement) { 66 | let insertPos = this.find(beforeElement); 67 | if(insertPos != -1) { 68 | this.dataStore.splice(insertPos+1,0,element); 69 | return true; 70 | } 71 | return false; 72 | }; 73 | 74 | function front () { 75 | this.pos = 0; 76 | }; 77 | 78 | function end () { 79 | this.pos = this.listSize-1; 80 | }; 81 | 82 | function prev () { 83 | --this.pos; 84 | }; 85 | 86 | function next () { 87 | ++this.pos; 88 | }; 89 | 90 | function moveTo (position) { 91 | this.pos = position; 92 | }; 93 | 94 | function getElement () { 95 | return this.dataStore[this.pos]; 96 | }; 97 | 98 | function contains (element) { 99 | return this.find(element) != -1 ? true : false; 100 | }; 101 | 102 | }; 103 | // test code 104 | var name = new list(); 105 | name.append("oven"); 106 | name.append("ovenzeze"); 107 | name.append("ovenzhang"); 108 | name.append("chanzen"); 109 | name.append("chanzen.zhang"); 110 | console.log(name.toString()); 111 | name.remove("chanzen.zhang"); 112 | console.log(name.toString()); 113 | name.insert("chanzen.zhang","oven"); 114 | console.log(name.toString()); 115 | console.log(name.getElement()); 116 | name.moveTo(2); 117 | console.log(name.getElement()); 118 | console.log(name.length()); 119 | -------------------------------------------------------------------------------- /src/js/max-distance-in-binary-tree.js: -------------------------------------------------------------------------------- 1 | // Question: 2 | // The diameter of a tree (sometimes called the width) is the number of nodes on the longest path between two leaves in the tree. The diagram below shows two trees each with diameter nine, the leaves that form the ends of a longest path are shaded (note that there is more than one path in each tree of length nine, but no path longer than nine nodes). 3 | 4 | // 二叉树 5 | function Node(data,left,right) { 6 | this.data = data; 7 | this.left = left; 8 | this.right = right; 9 | this.show = show; 10 | } 11 | 12 | function show () { 13 | return this.data; 14 | } 15 | 16 | // 二叉查找树(BST) 17 | function BST() { 18 | this.root = null; 19 | this.insert = insert;//插入节点 20 | this.diamter = diamter;//查找二叉树节点间的最大距离 21 | }; 22 | 23 | function insert(data) { 24 | let n = new Node(data,null,null); 25 | if(this.root == null) { 26 | this.root = n; 27 | }else { 28 | let current = this.root; 29 | let parent; 30 | while(true) { 31 | parent = current; 32 | if(data < current.data) { 33 | current = current.left; 34 | if(current == null) { 35 | parent.left = n; 36 | break; 37 | } 38 | } 39 | else { 40 | current = current.right; 41 | if(current == null) { 42 | parent.right = n; 43 | break; 44 | } 45 | } 46 | } 47 | } 48 | }; 49 | 50 | function diamter(node) { 51 | let lHeight, 52 | rHeight, 53 | lDiamter, 54 | rDiamter; 55 | // this function computed the Height of a child tree 56 | // Height is the longest path from the root node to the leaf node 57 | function height(node) { 58 | if(node == null) { 59 | return 0; 60 | } 61 | return 1 + Math.max(height(node.left),height(node.right)); 62 | } 63 | // Height end 64 | 65 | if(node == null) { 66 | return 0; 67 | } 68 | // computed Height of the left&right sub Tree 69 | lHeight = height(node.left); 70 | rHeight = height(node.right); 71 | // computed diamter of the left&right sub Tree 72 | lDiamter = diamter(node.left); 73 | rDiamter = diamter(node.right); 74 | // return the max value of following: 75 | // 1: the diamter of left sub tree 76 | // 2: the diamter of right sub tree 77 | // 3: Height of left sub tree + Height of right sub tree + 1 78 | return Math.max(lHeight + rHeight + 1, Math.max(diamter(node.left),diamter(node.right))); 79 | } 80 | 81 | // test code 82 | let nums = new BST(); 83 | nums.insert(23); 84 | nums.insert(16); 85 | nums.insert(3); 86 | nums.insert(22); 87 | nums.insert(21); 88 | nums.insert(22); 89 | nums.insert(45); 90 | nums.insert(37); 91 | console.log(`最远距离为:${diamter(nums.root)}`); 92 | -------------------------------------------------------------------------------- /src/js/max-width-of-binary-tree.js: -------------------------------------------------------------------------------- 1 | // Question: 2 | // Maximum width of a binary tree 3 | // Given a binary tree, write a function to get the maximum width of the given tree. Width of a tree is maximum of widths of all levels. 4 | // 5 | // Let us consider the below example tree. 6 | // 7 | // 1 8 | // / \ 9 | // 2 3 10 | // / \ \ 11 | // 4 5 8 12 | // / \ 13 | // 6 7 14 | // For the above tree, 15 | // width of level 1 is 1, 16 | // width of level 2 is 2, 17 | // width of level 3 is 3, 18 | // width of level 4 is 2. 19 | // So the maximum width of the tree is 3. 20 | 21 | function maxWidth(node) { 22 | let height, 23 | maxWidth = 0; 24 | // this function computed the max height of binary tree 25 | function getHeight(node) { 26 | let lHeight, 27 | rHeight; 28 | if(node == null) { 29 | return 0; 30 | }else { 31 | lHeight = getHeight(node.left); 32 | rHeight = getHeight(node.right); 33 | return (lHeight > rHeight ? lHeight + 1 : rHeight + 1); 34 | } 35 | } 36 | // this function computed width of given level 37 | function getWidth(node,level) { 38 | if(!node){ 39 | return 0; 40 | } 41 | if(level == 1) { 42 | return 1; 43 | }else if(level > 1) { 44 | return (getWidth(node.left, level - 1) + getWidth(node.right, level - 1)); 45 | } 46 | } 47 | 48 | height = getHeight(node);//get the height of binary tree 49 | for(let i = 1;i < height + 1;i++) { 50 | width = getWidth(node, i); 51 | if(width > maxWidth) { 52 | maxWidth = width; 53 | } 54 | } 55 | return maxWidth; 56 | } 57 | 58 | // 二叉树 59 | function Node(data,left,right) { 60 | this.data = data; 61 | this.left = left; 62 | this.right = right; 63 | this.show = show; 64 | } 65 | 66 | function show () { 67 | return this.data; 68 | } 69 | 70 | // 二叉查找树(BST) 71 | function BST() { 72 | this.root = null; 73 | this.insert = insert;//插入节点 74 | this.maxWidth = maxWidth;//查找二叉树节点间的最大距离 75 | }; 76 | 77 | function insert(data) { 78 | let n = new Node(data,null,null); 79 | if(this.root == null) { 80 | this.root = n; 81 | }else { 82 | let current = this.root; 83 | let parent; 84 | while(true) { 85 | parent = current; 86 | if(data < current.data) { 87 | current = current.left; 88 | if(current == null) { 89 | parent.left = n; 90 | break; 91 | } 92 | } 93 | else { 94 | current = current.right; 95 | if(current == null) { 96 | parent.right = n; 97 | break; 98 | } 99 | } 100 | } 101 | } 102 | }; 103 | 104 | // test code 105 | let nums = new BST(); 106 | nums.insert(23); 107 | nums.insert(16); 108 | nums.insert(3); 109 | nums.insert(22); 110 | nums.insert(21); 111 | nums.insert(22); 112 | nums.insert(45); 113 | nums.insert(37); 114 | console.log(`最大宽度为:${maxWidth(nums.root)}`); 115 | -------------------------------------------------------------------------------- /src/js/min-absolute-difference-in-binary-tree.js: -------------------------------------------------------------------------------- 1 | // 二叉树 2 | function Node(data,left,right) { 3 | this.data = data; 4 | this.left = left; 5 | this.right = right; 6 | this.show = show; 7 | } 8 | 9 | function show () { 10 | return this.data; 11 | } 12 | 13 | // 二叉查找树(BST) 14 | function BST() { 15 | this.root = null; 16 | this.insert = insert;//插入节点 17 | this.minAbs = minAbs;//查找二叉树最小深度 18 | }; 19 | 20 | function insert(data) { 21 | let n = new Node(data,null,null); 22 | if(this.root == null) { 23 | this.root = n; 24 | }else { 25 | let current = this.root; 26 | let parent; 27 | while(true) { 28 | parent = current; 29 | if(data < current.data) { 30 | current = current.left; 31 | if(current == null) { 32 | parent.left = n; 33 | break; 34 | } 35 | } 36 | else { 37 | current = current.right; 38 | if(current == null) { 39 | parent.right = n; 40 | break; 41 | } 42 | } 43 | } 44 | } 45 | }; 46 | // leetCode: 47 | // Given a binary search tree with non-negative values, find the minimum absolute difference between values of any two nodes. 48 | function minAbs(node,val = {prev: undefined,min: Number.MAX_VALUE}){ 49 | if(!node) { 50 | return; 51 | } 52 | minAbs(node.left,val); 53 | if( val.prev >= 0) { 54 | val.min = Math.min(val.min, Math.abs(val.prev - node.data)); 55 | } 56 | val.prev = node.data; 57 | minAbs(node.right,val); 58 | return val.min; 59 | } 60 | 61 | // test code 62 | let nums = new BST(); 63 | nums.insert(23); 64 | nums.insert(16); 65 | nums.insert(3); 66 | nums.insert(20); 67 | nums.insert(18); 68 | nums.insert(25); 69 | nums.insert(45); 70 | nums.insert(37); 71 | console.log(`最小绝对值为:${minAbs(nums.root)}`); 72 | -------------------------------------------------------------------------------- /src/js/min-depths-of-binary-tree.js: -------------------------------------------------------------------------------- 1 | // 二叉树 2 | function Node(data,left,right) { 3 | this.data = data; 4 | this.left = left; 5 | this.right = right; 6 | this.show = show; 7 | } 8 | 9 | function show () { 10 | return this.data; 11 | } 12 | 13 | // 二叉查找树(BST) 14 | function BST() { 15 | this.root = null; 16 | this.insert = insert;//插入节点 17 | this.minDepths = minDepths;//查找二叉树最小深度 18 | }; 19 | 20 | function insert(data) { 21 | let n = new Node(data,null,null); 22 | if(this.root == null) { 23 | this.root = n; 24 | }else { 25 | let current = this.root; 26 | let parent; 27 | while(true) { 28 | parent = current; 29 | if(data < current.data) { 30 | current = current.left; 31 | if(current == null) { 32 | parent.left = n; 33 | break; 34 | } 35 | } 36 | else { 37 | current = current.right; 38 | if(current == null) { 39 | parent.right = n; 40 | break; 41 | } 42 | } 43 | } 44 | } 45 | }; 46 | 47 | // 查找二叉树最小深度 48 | // 根节点为空,返回0; 49 | // 只有左(右)子节点,返回1; 50 | // 如果左右节点都不为空,则分别计算左子树和右子数的深度,最小深度就是这两者的深度中的较小值; 51 | function minDepths(node,minDeep) { 52 | minDeep = minDeep ? minDeep : 1; 53 | if(node.left == null || node.right == null) { 54 | return minDeep; 55 | }else { 56 | minDeep++; 57 | return Math.min(minDepths(node.left,minDeep),minDepths(node.right,minDeep)); 58 | } 59 | }; 60 | 61 | // test code 62 | let nums = new BST(); 63 | nums.insert(23); 64 | nums.insert(16); 65 | nums.insert(3); 66 | nums.insert(22); 67 | nums.insert(21); 68 | nums.insert(22); 69 | nums.insert(45); 70 | nums.insert(37); 71 | console.log(`最小深度为:${minDepths(nums.root)}`); 72 | -------------------------------------------------------------------------------- /src/js/queue.js: -------------------------------------------------------------------------------- 1 | // 队列也是一种特殊的列表,和栈不同的是,队列是一种先进先出的数据结构, 2 | // 只能在队首删除元素,在队尾添加元素。(这也是名字的来源) 3 | 4 | function queue() { 5 | this.dataStore = []; 6 | // 入队,从队尾添加元素 7 | this.enqueue = enqueue; 8 | // 出队,从队首删除元素 9 | this.dequeue = dequeue; 10 | // 返回队首元素 11 | this.front = front; 12 | // 返回队尾的元素 13 | this.back = back; 14 | // 显示队列中所有元素 15 | this.display = display; 16 | // 判断队列是否为空 17 | this.isEmpty = isEmpty; 18 | } 19 | 20 | function enqueue(element) { 21 | this.dataStore.push(element); 22 | } 23 | 24 | function dequeue() { 25 | return this.dataStore.shift(); 26 | } 27 | 28 | function front() { 29 | return this.dataStore[0]; 30 | } 31 | 32 | function back() { 33 | return this.dataStore[this.dataStore.length - 1]; 34 | } 35 | 36 | function display() { 37 | return this.dataStore.slice(); 38 | } 39 | 40 | function isEmpty() { 41 | return this.dataStore.length ? false : true; 42 | } 43 | 44 | // test code 45 | let q = new queue(); 46 | q.enqueue("oven"); 47 | q.enqueue("ovenzeze"); 48 | q.enqueue("chanzen"); 49 | q.enqueue("chanzen_zhang"); 50 | q.enqueue("clay"); 51 | q.enqueue("clay_zhang"); 52 | console.log(`the queue is : ${q.display()}`); 53 | q.dequeue(); 54 | console.log(`after dequeue the queue is : ${q.display()}`); 55 | console.log(`front of queue is : ${q.front()}`); 56 | console.log(`back of queue is : ${q.back()}`); 57 | console.log(`queue is empty : ${q.isEmpty()}`); -------------------------------------------------------------------------------- /src/js/reverse-binary-tree.js: -------------------------------------------------------------------------------- 1 | // Question: 2 | // Mirror of a Tree: Mirror of a Binary Tree T is another Binary Tree M(T) with left and right // children of all non-leaf nodes interchanged. 3 | 4 | function reverse(node) { 5 | let left, 6 | right; 7 | if(node == null) { 8 | return node; 9 | } 10 | left = reverse(node.left); 11 | right = reverse(node.right); 12 | node.left = right; 13 | node.right = left; 14 | return node; 15 | } 16 | 17 | // 二叉树 18 | function Node(data,left,right) { 19 | this.data = data; 20 | this.left = left; 21 | this.right = right; 22 | this.show = show; 23 | } 24 | 25 | function show () { 26 | return this.data; 27 | } 28 | 29 | // 二叉查找树(BST) 30 | function BST() { 31 | this.root = null; 32 | this.insert = insert;//插入节点 33 | this.preOrder = preOrder;//先序遍历二叉树 34 | this.reverse = reverse;//mirror the tree 35 | }; 36 | 37 | function insert(data) { 38 | let n = new Node(data,null,null); 39 | if(this.root == null) { 40 | this.root = n; 41 | }else { 42 | let current = this.root; 43 | let parent; 44 | while(true) { 45 | parent = current; 46 | if(data < current.data) { 47 | current = current.left; 48 | if(current == null) { 49 | parent.left = n; 50 | break; 51 | } 52 | } 53 | else { 54 | current = current.right; 55 | if(current == null) { 56 | parent.right = n; 57 | break; 58 | } 59 | } 60 | } 61 | } 62 | }; 63 | // 先序遍历 64 | // 先访问根节点,然后以同样的方式访问左子树和右子树 65 | function preOrder (node) { 66 | if(!(node == null)) { 67 | console.log(node.show()); 68 | preOrder(node.left); 69 | preOrder(node.right); 70 | } 71 | }; 72 | 73 | // test code 74 | let nums = new BST(); 75 | nums.insert(23); 76 | nums.insert(16); 77 | nums.insert(3); 78 | nums.insert(22); 79 | nums.insert(21); 80 | nums.insert(45); 81 | nums.insert(37); 82 | console.log(`翻转前先序遍历结果`); 83 | preOrder(nums.root); 84 | nums.reverse(nums.root); 85 | console.log(`翻转后先序遍历结果`); 86 | preOrder(nums.root); 87 | // console.log(`翻转后先序遍历结果为:${preOrder(nums.root)}`); 88 | -------------------------------------------------------------------------------- /src/js/self-organization-search.js: -------------------------------------------------------------------------------- 1 | // 对于未排序的数据来说,当被查找的数据位于数据集的起始位置时, 2 | // 查找的速度是最快的。 3 | // 自组织查找的策略就是:将频繁被查找的数据放到数据集的靠前位置(前20%) 4 | // 来最小化查找的次数。 5 | 6 | function selfOrgSearch(arr, data) { 7 | let len = arr.length; 8 | for (let i = 0; i < len; i++) { 9 | if (arr[i] === data && i > len * 0.2) { 10 | swap(arr, i, 0); 11 | return true; 12 | } else if (arr[i] === data) { 13 | return true; 14 | } 15 | } 16 | 17 | function swap(arr, indexCurr, indexOrig) { 18 | let temp = arr[indexCurr]; 19 | arr[indexCurr] = arr[indexOrig]; 20 | arr[indexOrig] = temp; 21 | } 22 | } 23 | 24 | // test 25 | let arrTest = []; 26 | for (let i = 0; i < 10; i++) { 27 | arrTest[i] = i * 11; 28 | } 29 | console.log(`origin array is : ${arrTest}`); 30 | selfOrgSearch(arrTest, 88); 31 | console.log(`after search 88 array is : ${arrTest}`); -------------------------------------------------------------------------------- /src/js/singly-linked-circular-list.js: -------------------------------------------------------------------------------- 1 | // 循环链表 2 | //基本实现和单向链表相同,主要区别是循环链表的最后一个节点指向头结点 3 | function Node(element) { 4 | this.element = element; 5 | this.next = null; 6 | } 7 | function linkedList() { 8 | this.head = new Node("head"); 9 | this.head.next = this.head; 10 | this.find = find; 11 | this.insert = insert; 12 | this.display = display; 13 | this.findPrev = findPrev; 14 | this.remove = remove; 15 | 16 | //display all element 17 | function display() { 18 | let currNode = this.head; 19 | while(currNode != null && currNode.next.element != "head") { 20 | console.log(currNode.next.element); 21 | currNode = currNode.next; 22 | } 23 | } 24 | 25 | // find the Node contain given item in linkedList and return Node 26 | function find(item) { 27 | let currNode = this.head; 28 | //退出循环可能是找到与item相同的值或到了链表的最后一个元素了,再判断一下当前值是否是item即可 29 | while(currNode.element != item && currNode.next.element != "head") { 30 | currNode = currNode.next; 31 | } 32 | if(currNode.element == item) { 33 | return currNode; 34 | } 35 | return -1; 36 | } 37 | 38 | // insert element after the given item,return true or false 39 | function insert(insertElement,item) { 40 | let newNode = new Node(insertElement); 41 | let insertPos = this.find(item); 42 | if(insertPos == -1) { 43 | return false; 44 | }else if(insertPos.next.element == "head") { 45 | insertPos.next = newNode; 46 | newNode.next = this.head; 47 | return true; 48 | }else { 49 | newNode.next = insertPos.next; 50 | insertPos.next = newNode; 51 | return true; 52 | } 53 | } 54 | 55 | // find the previous one of the Node contain given item,return the previous Node 56 | function findPrev(item) { 57 | let currNode = this.head; 58 | while(currNode.next.element != item && currNode.next.element != "head") { 59 | currNode = currNode.next; 60 | } 61 | if(currNode.next.element == item) { 62 | return currNode; 63 | } 64 | return -1; 65 | } 66 | 67 | // remove the Node contain given item,return true or false 68 | function remove(item) { 69 | let removePosPrev = this.findPrev(item); 70 | let removePos = this.find(item); 71 | if(removePosPrev == -1) { 72 | return false; 73 | }else if (removePos.next.element == "head") { 74 | removePosPrev.next = this.head; 75 | return true; 76 | }else { 77 | removePosPrev.next = removePos.next; 78 | return true; 79 | } 80 | } 81 | 82 | } 83 | // test 84 | let linkedListTest = new linkedList(); 85 | linkedListTest.insert("oven", "head"); 86 | linkedListTest.insert("ovenzeze", "oven"); 87 | linkedListTest.insert("ovenerly", "ovenzeze"); 88 | linkedListTest.insert("chanzen", "ovenerly"); 89 | linkedListTest.insert("chanzen.zhang", "chanzen"); 90 | linkedListTest.display(); 91 | linkedListTest.remove("chanzen.zhang"); 92 | console.log("after remove [chanzen.zhang]"); 93 | linkedListTest.display(); 94 | -------------------------------------------------------------------------------- /src/js/stack.js: -------------------------------------------------------------------------------- 1 | // 栈是一种后入先出的数据结构,其实是一种特殊的列表,栈内的元素只能通过 2 | // 列表的一端访问,这一端称为栈顶。所以任何不在栈顶的元素都无法访问,为了 3 | // 访问到栈底的元素,必须先拿到上面的元素。 4 | 5 | function stack() { 6 | this.dataStore = []; 7 | // Top,记录栈顶位置 8 | this.top = 0; 9 | // 入栈,将一个元素压入栈,并返回该元素 10 | this.push = push; 11 | // 出栈,将一个元素弹出栈,并返回该元素 12 | this.pop = pop; 13 | // 返回栈顶元素,并不删除 14 | this.peek = peek; 15 | // 清除栈内的所有元素 16 | this.clear = clear; 17 | // 记录栈内元素的个数 18 | this.length = length; 19 | } 20 | 21 | function push(element) { 22 | this.dataStore[this.top++] = element; 23 | } 24 | 25 | function peek() { 26 | // 返回栈顶元素,Top值是从1开始计数,数组访问从0开始 27 | // 此处要明确top--和top-1的区别 28 | return this.dataStore[this.top - 1]; 29 | } 30 | 31 | function pop() { 32 | // 返回栈顶元素 同时将Top值减1,即删除栈顶元素 33 | return this.dataStore[--this.top]; 34 | } 35 | 36 | function clear() { 37 | this.top = 0; 38 | } 39 | 40 | function length() { 41 | return this.top; 42 | } 43 | 44 | // test 45 | let testStack = new stack(); 46 | testStack.push("oven"); 47 | testStack.push("oven_zhang"); 48 | testStack.push("chanzen"); 49 | testStack.push("chanzen_zhang"); 50 | testStack.push("clay"); 51 | testStack.push("clay_zhang"); 52 | console.log(testStack.length()); 53 | console.log(testStack.peek()); 54 | console.log(testStack.pop()); 55 | console.log(testStack.peek()); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "importHelpers": true, 5 | "moduleResolution": "node", 6 | "experimentalDecorators": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "sourceMap": true, 10 | "skipLibCheck": true, 11 | "outDir": "dist", 12 | "rootDir": "src", 13 | "target": "es2017" 14 | }, 15 | "exclude": [ 16 | "node_modules" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": "tslint:recommended", 4 | "rules": { 5 | "no-duplicate-imports": true, 6 | "no-parameter-reassignment": false, 7 | "trailing-comma": false, 8 | "radix": false, 9 | "ordered-imports": false, 10 | "arrow-parens": false, 11 | "no-console": [ 12 | false 13 | ], 14 | "semicolon": [ 15 | true, 16 | "never" 17 | ], 18 | "indent": [true, "spaces", 2], 19 | "object-literal-sort-keys": false, 20 | "variable-name": false, 21 | "quotemark": false, 22 | "no-string-literal": false, 23 | "cyclomatic-complexity": false, 24 | "max-line-length": [ 25 | false 26 | ], 27 | "one-variable-per-declaration": false, 28 | "max-classes-per-file": [ 29 | true, 30 | 5 31 | ] 32 | }, 33 | "linterOptions": { 34 | "exclude": ["src/**/*.d.ts"] 35 | } 36 | } --------------------------------------------------------------------------------