├── README.md
├── design-patterns
├── README.md
├── 代理模式
│ ├── README.md
│ └── index.html
├── 适配器模式
│ ├── README.md
│ └── index.html
├── 单例模式
│ ├── README.md
│ └── index.html
└── 工厂模式
│ ├── README.md
│ └── index.html
├── .DS_Store
├── flutter
├── 1.png
└── README.md
├── algorithm
├── .DS_Store
├── 图
│ └── README.md
├── 堆
│ ├── imgs
│ │ ├── 1.png
│ │ ├── 10.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ ├── 4.png
│ │ ├── 5.png
│ │ ├── 6.png
│ │ ├── 7.png
│ │ ├── 8.png
│ │ └── 9.png
│ ├── 大顶堆.html
│ ├── 堆.html
│ └── RRADME.md
├── 树
│ ├── .DS_Store
│ ├── imgs
│ │ ├── 1.png
│ │ ├── 2.png
│ │ └── 3.png
│ ├── 排序二叉树.html
│ ├── README.md
│ └── 完全二叉树.html
└── 链表
│ ├── imgs
│ ├── 5.png
│ ├── 6.png
│ ├── 1.webp
│ ├── 2.webp
│ ├── 3.webp
│ ├── 4.webp
│ └── 7.webp
│ ├── 双向链表.html
│ ├── 单向链表.html
│ ├── 反向链表.html
│ └── README.md
└── gpu
├── 一维数组测试
├── cpu1.html
├── gpu1.html
├── gpu2.html
└── gpu3.html
├── README.md
└── 二维数组测试
└── gpu1.html
/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/design-patterns/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/design-patterns/代理模式/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/.DS_Store
--------------------------------------------------------------------------------
/flutter/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/flutter/1.png
--------------------------------------------------------------------------------
/algorithm/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/.DS_Store
--------------------------------------------------------------------------------
/algorithm/图/README.md:
--------------------------------------------------------------------------------
1 | # 参考文章
2 |
3 | - [图的基本算法(BFS和DFS)](https://www.jianshu.com/p/70952b51f0c8)
--------------------------------------------------------------------------------
/algorithm/堆/imgs/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/堆/imgs/1.png
--------------------------------------------------------------------------------
/algorithm/堆/imgs/10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/堆/imgs/10.png
--------------------------------------------------------------------------------
/algorithm/堆/imgs/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/堆/imgs/2.png
--------------------------------------------------------------------------------
/algorithm/堆/imgs/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/堆/imgs/3.png
--------------------------------------------------------------------------------
/algorithm/堆/imgs/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/堆/imgs/4.png
--------------------------------------------------------------------------------
/algorithm/堆/imgs/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/堆/imgs/5.png
--------------------------------------------------------------------------------
/algorithm/堆/imgs/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/堆/imgs/6.png
--------------------------------------------------------------------------------
/algorithm/堆/imgs/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/堆/imgs/7.png
--------------------------------------------------------------------------------
/algorithm/堆/imgs/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/堆/imgs/8.png
--------------------------------------------------------------------------------
/algorithm/堆/imgs/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/堆/imgs/9.png
--------------------------------------------------------------------------------
/algorithm/树/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/树/.DS_Store
--------------------------------------------------------------------------------
/algorithm/树/imgs/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/树/imgs/1.png
--------------------------------------------------------------------------------
/algorithm/树/imgs/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/树/imgs/2.png
--------------------------------------------------------------------------------
/algorithm/树/imgs/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/树/imgs/3.png
--------------------------------------------------------------------------------
/algorithm/链表/imgs/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/链表/imgs/5.png
--------------------------------------------------------------------------------
/algorithm/链表/imgs/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/链表/imgs/6.png
--------------------------------------------------------------------------------
/algorithm/链表/imgs/1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/链表/imgs/1.webp
--------------------------------------------------------------------------------
/algorithm/链表/imgs/2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/链表/imgs/2.webp
--------------------------------------------------------------------------------
/algorithm/链表/imgs/3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/链表/imgs/3.webp
--------------------------------------------------------------------------------
/algorithm/链表/imgs/4.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/链表/imgs/4.webp
--------------------------------------------------------------------------------
/algorithm/链表/imgs/7.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wscats/awesome/master/algorithm/链表/imgs/7.webp
--------------------------------------------------------------------------------
/design-patterns/适配器模式/README.md:
--------------------------------------------------------------------------------
1 | # 结构型模式
2 |
3 | - 适配器模式主要解决两个接口之间不匹配的问题,不会改变原有的接口,而是由一个对象对另一个对象的包装。
4 | - 适配器模式符合开放封闭原则
5 |
6 | # 总结
7 |
8 | 类似一个过滤器,把接口经过一个代理函数去新增或者重写其他接口
--------------------------------------------------------------------------------
/flutter/README.md:
--------------------------------------------------------------------------------
1 | # 安装
2 |
3 | [官网下载SDK](https://flutter.dev/docs/development/tools/sdk/releases?tab=macos#macos)
4 |
5 | 解压下载好的flutter文件,进入`flutter/bin`文件夹里面,运行以下命令检查是否安装成功。
6 |
7 | ```js
8 | ./flutter
9 | ```
10 |
11 |
--------------------------------------------------------------------------------
/design-patterns/单例模式/README.md:
--------------------------------------------------------------------------------
1 | - 1.单例模式的主要思想就是,实例如果已经创建,则直接返回
2 |
3 | ```js
4 | function creatSingleton() {
5 | var obj = null
6 | // 实例如已经创建过,直接返回
7 | if (!obj) {
8 | obj = xxx
9 | }
10 | return obj
11 | }
12 | ```
13 |
14 | - 2.符合开放封闭原则
--------------------------------------------------------------------------------
/design-patterns/工厂模式/README.md:
--------------------------------------------------------------------------------
1 | # 工厂模式
2 |
3 | 工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象,用工厂方法代替new操作的一种模式。
4 |
5 | ```js
6 | class Creator {
7 | create(name) {
8 | return new Animal(name)
9 | }
10 | }
11 |
12 | class Animal {
13 | constructor(name) {
14 | this.name = name
15 | }
16 | }
17 |
18 | var creator = new Creator()
19 |
20 | var duck = creator.create('Duck')
21 | console.log(duck.name) // Duck
22 |
23 | var chicken = creator.create('Chicken')
24 | console.log(chicken.name) // Chicken
25 | ```
26 |
27 | - 构造函数和创建者分离,对new操作进行封装
28 | - 符合开放封闭原则
29 |
--------------------------------------------------------------------------------
/gpu/一维数组测试/cpu1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
24 |
25 | - 根节点:二叉树最顶层的节点
26 | - 分支节点:除了根节点以外且拥有叶子节点
27 | - 叶子节点:除了自身,没有其他子节点
28 |
29 | ## 二叉树的一些公式
30 |
31 | 1. 第n层的节点数最多为2n个节点
32 | 2. n层二叉树最多有`2^0 + ... + 2^n = 2^(n+1) - 1`个节点
33 | 3. 第一个非叶子节点:length/2
34 | 4. 一个节点的孩子节点:2n、2n+1
35 |
36 | ## 树和二叉树的三个主要差别
37 |
38 | - 树的节点个数至少为1,而二叉树的节点个数可以为0
39 | - 树中节点的最大度数(节点数量)没有限制,而二叉树的节点的最大度数为2
40 | - 树的节点没有左右之分,而二叉树的节点有左右之分
41 |
42 | ## 二叉树分类
43 |
44 | - 满二叉树:一棵深度为k且有2^k - 1个节点的二叉树称为满二叉树
45 | - 完全二叉树:完全二叉树是指最后一层左边是满的,右边可能满也可能不满,然后其余层都是满的二叉树称为完全二叉树(满二叉树也是一种完全二叉树)
46 |
47 | ## 排序二叉树 / 搜索二叉树
48 |
49 |
50 |
51 | 左子树小于根节点,右子树大于根节点,子树也满足这样的条件,这样的树叫做排序二叉树。
52 | ```js
53 | function BinaryTree() {
54 | // 节点
55 | var Node = function (key) {
56 | // 节点值
57 | this.key = key;
58 | // 左叶子
59 | this.left = null;
60 | // 右叶子
61 | this.right = null;
62 | };
63 | // 根节点
64 | this.root = null;
65 | // 插入节点
66 | var insertNode = function (node, newNode) {
67 | // 对比值 新值小于根(该)节点值,放左边
68 | if (newNode.key < node.key) {
69 | // 左边如果为空直接放入
70 | if (node.left === null) {
71 | node.left = newNode;
72 | // 左边如果不为空把节点取出来继续往下面对比
73 | } else {
74 | insertNode(node.left, newNode);
75 | }
76 | } else {
77 | if (node.right === null) {
78 | node.right = newNode;
79 | } else {
80 | insertNode(node.right, newNode);
81 | }
82 | }
83 | };
84 | this.insert = function (key) {
85 | // 创建节点
86 | var newnode = new Node(key);
87 | // 如果this.root为空,也就是第一个为根节点,否则插入节点
88 | if (this.root === null) {
89 | this.root = newnode;
90 | } else {
91 | insertNode(this.root, newnode);
92 | }
93 | };
94 | }
95 |
96 | // 数组存放没放入排序二叉树的节点
97 | var nodes = [8, 3, 10, 1, 6, 14, 4, 7, 13];
98 | var binaryTree = new BinaryTree;
99 | nodes.forEach(function (key) {
100 | binaryTree.insert(key);
101 | });
102 | console.log(binaryTree);
103 | ```
104 |
105 | 数据结构
106 |
107 |
108 |
109 | # 遍历
110 |
111 | - 中序遍历(inorder):先遍历左节点,再遍历自己,最后遍历右节点,输出的刚好是**有序的列表**是一种排序方案
112 | - 前序遍历(preorder):先自己,再遍历左节点,最后遍历右节点
113 | - 后序遍历(postorder):先左节点,再右节点,最后自己
114 |
115 |
--------------------------------------------------------------------------------
/algorithm/链表/双向链表.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
19 |
20 |
21 | ## 堆排序算法
22 |
23 | - 将初始二叉树转化为大顶堆(heapify)(实质是从第一个非叶子结点开始,从下至上,从右至左,对每一个非叶子结点做shiftDown操作),此时根结点为最大值,将其与最后一个结点交换。
24 | - 除开最后一个结点,将其余节点组成的新堆转化为大顶堆(实质上是对根节点做shiftDown操作),此时根结点为次最大值,将其与最后一个结点交换。
25 | - 重复步骤2,直到堆中元素个数为1(或其对应数组的长度为1),排序完成。
26 |
27 | ### 步骤1:
28 |
29 | 初始化大顶堆,首先选取最后一个非叶子结点(我们只需要调整父节点和孩子节点之间的大小关系,叶子结点之间的大小关系无需调整)。设数组为arr,则第一个非叶子结点的下标为:`i = Math.floor(arr.length/2 - 1) = 1`,也就是数字4,如图中虚线框,找到三个数字的最大值,与父节点交换。
30 |
31 |
32 |
33 | 然后,下标 i 依次减1(即从第一个非叶子结点开始,从右至左,从下至上遍历所有非叶子节点)。后面的每一次调整都是如此:找到父子结点中的最大值,做交换。
34 |
35 |
36 |
37 | 这一步中数字6、1交换后,数字[1,5,4]组成的堆顺序不对,需要执行一步调整。因此需要注意,每一次对一个非叶子结点做调整后,都要观察是否会影响子堆顺序!
38 |
39 |
40 |
41 | 这次调整后,根节点为最大值,形成了一个大顶堆,将根节点与最后一个结点交换。
42 |
43 | ### 步骤2:
44 |
45 | 除开当前最后一个结点6(即最大值),将其余结点[4,5,3,1]组成新堆转化为大顶堆(注意观察,此时根节点以外的其他结点,都满足大顶堆的特征,所以可以从根节点4开始调整,即找到4应该处于的位置即可)。
46 |
47 |
48 |
49 |
50 |
51 | ### 步骤3:
52 |
53 | 接下来反复执行步骤2,直到堆中元素个数为1:
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | 堆中元素个数为1, 排序完成。
62 |
63 | ### 代码实现
64 |
65 | ```js
66 | // 交换两个节点
67 | function swap(A, i, j) {
68 | let temp = A[i];
69 | A[i] = A[j];
70 | A[j] = temp;
71 | }
72 |
73 | // 将 i 结点以下的堆整理为大顶堆,注意这一步实现的基础实际上是:
74 | // 假设 结点 i 以下的子堆已经是一个大顶堆,shiftDown函数实现的
75 | // 功能是实际上是:找到 结点 i 在包括结点 i 的堆中的正确位置。后面
76 | // 将写一个 for 循环,从第一个非叶子结点开始,对每一个非叶子结点
77 | // 都执行 shiftDown操作,所以就满足了结点 i 以下的子堆已经是一大
78 | //顶堆
79 | function shiftDown(A, i, length) {
80 | let temp = A[i]; // 当前父节点
81 | // j
18 |
19 | 链表是一组节点组成的集合,每个节点都使用一个对象的引用来指向它的后一个节点。
20 |
21 | 其中,data中保存着数据,next保存着下一个链表的引用。上图中,我们说 data2 跟在 data1 后面,而不是说 data2 是链表中的第二个元素。上图,值得注意的是,我们将链表的尾元素指向了 null 节点,表示链接结束的位置。
22 |
23 | ### 有头节点的链表
24 |
25 | 由于链表的起始点的确定比较麻烦,因此很多链表的实现都会在链表的最前面添加一个特殊的节点,称为 头节点,表示链表的头部。进行改造,链表就成了如下的样子:
26 |
27 |
28 |
29 | ### 插入节点
30 |
31 | 向链表中插入一个节点的效率很高,需要修改它前面的节点(前驱),使其指向新加入的节点,而将新节点指向原来前驱节点指向的节点即可。下面我将用图片演示如何在 data2 节点 后面插入 data4 节点。
32 |
33 |
34 |
35 | ### 删除节点
36 |
37 | 同样,从链表中删除一个节点,也很简单。只需将待删节点的前驱节点指向待删节点的,同时将待删节点指向null,那么节点就删除成功了。下面我们用图片演示如何从链表中删除 data4 节点。
38 |
39 |
40 |
41 | # 链表的设计
42 |
43 | 我们设计链表包含两个类,一个是 Node 类用来表示节点,另一个事 LinkedList 类提供插入节点、删除节点等一些操作。
44 |
45 |
46 | ## Node类
47 |
48 | Node类包含连个属性: element 用来保存节点上的数据,next 用来保存指向下一个节点的链接,具体实现如下:
49 |
50 | ```js
51 | //节点
52 | function Node(element) {
53 | this.element = element; //当前节点的元素
54 | this.next = null; //下一个节点链接
55 | }
56 | ```
57 |
58 | ## LinkedList类
59 |
60 | LinkedList类提供了对链表进行操作的方法,包括插入删除节点,查找给定的值等。值得注意的是,它只有一个
61 | 属性,那就是使用一个 Node 对象来保存该链表的头节点。
62 |
63 | 它的构造函数的实现如下:
64 |
65 | ```js
66 | //链表类
67 | function LList () {
68 | this.head = new Node( 'head' ); //头节点
69 | this.find = find; //查找节点
70 | this.insert = insert; //插入节点
71 | this.remove = remove; //删除节点
72 | this.findPrev = findPrev; //查找前一个节点
73 | this.display = display; //显示链表
74 | }
75 | ```
76 |
77 | head节点的next属性初始化为 null ,当有新元素插入时,next会指向新的元素。
78 |
79 | 接下来,我们来看看具体方法的实现。
80 |
81 | ### insert:向链表插入一个节点
82 |
83 | 我们先分析分析insert方法,想要插入一个节点,我们必须明确要在哪个节点的前面或后面插入。我们先来看看,如何在一个已知节点的后面插入一个节点。
84 |
85 | 在一个已知节点后插入新节点,我们首先得找到该节点,为此,我们需要一个 find 方法用来遍历链表,查找给定的数据。如果找到,该方法就返回保存该数据的节点。那么,我们先实现 find 方法。
86 |
87 |
88 | ### find:查找给定节点
89 |
90 | ```js
91 | //查找给定节点
92 |
93 | function find ( item ) {
94 | var currNode = this.head;
95 | while ( currNode.element != item ){
96 | currNode = currNode.next;
97 | }
98 | return currNode;
99 | }
100 | ```
101 |
102 | find 方法同时展示了如何在链表上移动。首先,创建一个新节点,将链表的头节点赋给这个新创建的节点,然后在链表上循环,如果当前节点的 element 属性和我们要找的信息不符,就将当前节点移动到下一个节点,如果查找成功,该方法返回包含该数据的节点;否则,就会返回null。
103 | 一旦找到了节点,我们就可以将新的节点插入到链表中了,将新节点的 next 属性设置为后面节点的 next 属性对应的值,然后设置后面节点的 next 属性指向新的节点,具体实现如下:
104 |
105 | ```js
106 | //插入节点
107 |
108 | function insert ( newElement , item ) {
109 | var newNode = new Node( newElement );
110 | var currNode = this.find( item );
111 | newNode.next = currNode.next;
112 | currNode.next = newNode;
113 | }
114 | ```
115 |
116 | 现在我们可以测试我们的链表了。等等,我们先来定义一个 display 方法显示链表的元素,不然我们怎么知道对不对呢?
117 |
118 | ### display:显示链表
119 |
120 | 这个方法其实跟`find`很相似,只是寻找的时候要判断 next 是否
121 | ```js
122 | //显示链表元素
123 |
124 | function display () {
125 | var currNode = this.head;
126 | while ( !(currNode.next == null) ){
127 | console.log( currNode.next.element );
128 | currNode = currNode.next;
129 | }
130 | }
131 | ```
132 |
133 | 实现原理同上,将头节点赋给一个新的变量,然后循环链表,直到当前节点的 next 属性为 null 时停止循环,我们循环过程中将每个节点的数据打印出来就好了。
134 | ```js
135 | var fruits = new LList();
136 |
137 | fruits.insert('Apple' , 'head');
138 | fruits.insert('Banana' , 'Apple');
139 | fruits.insert('Pear' , 'Banana');
140 |
141 | console.log(fruits.display()); // Apple
142 | // Banana
143 | // Pear
144 | ```
145 |
146 | ### remove:从链表中删除一个节点
147 |
148 | 从链表中删除节点时,我们先要找个待删除节点的前一个节点,找到后,我们修改它的 next 属性,使其不在指向待删除的节点,而是待删除节点的下一个节点。那么,我们就得需要定义一个 findPrevious 方法遍历链表,检查每一个节点的下一个节点是否存储待删除的数据。如果找到,返回该节点,这样就可以修改它的 next 属性了。 findPrevious 的实现如下:
149 | ```js
150 | //查找带删除节点的前一个节点
151 |
152 | function findPrev( item ) {
153 | var currNode = this.head;
154 | while ( !( currNode.next == null) && ( currNode.next.element != item )){
155 | currNode = currNode.next;
156 | }
157 | return currNode;
158 | }
159 | ```
160 |
161 | 这样,remove 方法的实现也就迎刃而解了,而删除的本质就是改变链表中某一个元素的指向,让它指向下下一个元素
162 | ```js
163 | //删除节点
164 |
165 | function remove ( item ) {
166 | var prevNode = this.findPrev( item );
167 | if( !( prevNode.next == null ) ){
168 | prevNode.next = prevNode.next.next;
169 | }
170 | }
171 | ```
172 | 我们接着写一段测试程序,测试一下 remove 方法:
173 | // 接着上面的代码,我们再添加一个水果
174 | ```js
175 | fruits.insert('Grape' , 'Pear');
176 | console.log(fruits.display()); // Apple
177 | // Banana
178 | // Pear
179 | // Grape
180 |
181 | // 我们把香蕉吃掉
182 |
183 | fruits.remove('Banana');
184 | console.log(fruits.display()); // Apple
185 | // Pear
186 | // Grape
187 | ```
188 |
189 | Great!成功了,现在你已经可以实现一个基本的单向链表了。
190 |
191 | ## 单向链表结构
192 |
193 |
194 |
195 | ```js
196 | display: f,
197 | insert: f,
198 | find: f,
199 | head: {
200 | element: "head", // Head
201 | next: {
202 | element: "Apple"
203 | next: {
204 | element: "Banana"
205 | next: {
206 | element: "Pear"
207 | next: null
208 | }
209 | }
210 | }
211 | }
212 | ```
213 |
214 | # 双向链表
215 |
216 | 要实现双向链表,首先需要给 Node 类增加一个 previous 属性:
217 | ```js
218 | //节点类
219 |
220 | function Node(element) {
221 | this.element = element; //当前节点的元素
222 | this.next = null; //下一个节点链接
223 | this.previous = null; //上一个节点链接
224 | }
225 | ```
226 |
227 | 双向链表的 insert 方法与单链表相似,但需要设置新节点的 previous 属性,使其指向该节点的前驱,定义如下:
228 | ```js
229 | //插入节点
230 | function insert ( newElement , item ) {
231 | var newNode = new Node( newElement );
232 | var currNode = this.find( item );
233 | newNode.next = currNode.next;
234 | newNode.previous = currNode;
235 | currNode.next = newNode;
236 | }
237 | ```
238 |
239 | 双向链表的删除 remove 方法比单链表效率高,不需要查找前驱节点,只要找出待删除节点,然后将该节点的前驱 next 属性指向待删除节点的后继,设置该节点后继 previous 属性,指向待删除节点的前驱即可。定义如下:
240 | //删除节点
241 | ```js
242 | function remove ( item ) {
243 | var currNode = this.find ( item );
244 | if( !( currNode.next == null ) ){
245 | currNode.previous.next = currNode.next;
246 | currNode.next.previous = currNode.previous;
247 | currNode.next = null;
248 | currNode.previous = null;
249 | }
250 | }
251 | ```
252 |
253 | ## 双向链表结构
254 |
255 | 双向比单向列表多了一个`previous`属性
256 |
257 |
258 | ```js
259 | display: f,
260 | insert: f,
261 | find: f,
262 | head: {
263 | element: "head", // Head
264 | previous: null,
265 | next: {
266 | element: "Apple"
267 | previous: {element:"head",next:Node,previous:null}
268 | next: null
269 | }
270 | }
271 | ```
272 |
273 | ## 反向链表
274 |
275 | 还有一些反向显示链表 dispReverse,查找链表最后一个元素 findLast 等方法,相信你已经有了思路,这里我给出一个基本双向链表的完成代码,供大家参考。
276 |
277 | ```js
278 | //节点
279 |
280 | function Node(element) {
281 | this.element = element; //当前节点的元素
282 | this.next = null; //下一个节点链接
283 | this.previous = null; //上一个节点链接
284 | }
285 |
286 | //链表类
287 |
288 | function LList () {
289 | this.head = new Node( 'head' );
290 | this.find = find;
291 | this.findLast = findLast;
292 | this.insert = insert;
293 | this.remove = remove;
294 | this.display = display;
295 | this.dispReverse = dispReverse;
296 | }
297 |
298 | //查找元素
299 |
300 | function find ( item ) {
301 | var currNode = this.head;
302 | while ( currNode.element != item ){
303 | currNode = currNode.next;
304 | }
305 | return currNode;
306 | }
307 |
308 | //查找链表中的最后一个元素
309 |
310 | function findLast () {
311 | var currNode = this.head;
312 | while ( !( currNode.next == null )){
313 | currNode = currNode.next;
314 | }
315 | return currNode;
316 | }
317 |
318 |
319 | //插入节点
320 |
321 | function insert ( newElement , item ) {
322 | var newNode = new Node( newElement );
323 | var currNode = this.find( item );
324 | newNode.next = currNode.next;
325 | newNode.previous = currNode;
326 | currNode.next = newNode;
327 | }
328 |
329 | //显示链表元素
330 |
331 | function display () {
332 | var currNode = this.head;
333 | while ( !(currNode.next == null) ){
334 | console.debug( currNode.next.element );
335 | currNode = currNode.next;
336 | }
337 | }
338 |
339 | //反向显示链表元素
340 |
341 | function dispReverse () {
342 | var currNode = this.findLast();
343 | while ( !( currNode.previous == null )){
344 | console.log( currNode.element );
345 | currNode = currNode.previous;
346 | }
347 | }
348 |
349 | //删除节点
350 |
351 | function remove ( item ) {
352 | var currNode = this.find ( item );
353 | if( !( currNode.next == null ) ){
354 | currNode.previous.next = currNode.next;
355 | currNode.next.previous = currNode.previous;
356 | currNode.next = null;
357 | currNode.previous = null;
358 | }
359 | }
360 |
361 | var fruits = new LList();
362 |
363 | fruits.insert('Apple' , 'head');
364 | fruits.insert('Banana' , 'Apple');
365 | fruits.insert('Pear' , 'Banana');
366 | fruits.insert('Grape' , 'Pear');
367 |
368 | console.log( fruits.display() ); // Apple
369 | // Banana
370 | // Pear
371 | // Grape
372 |
373 | console.log( fruits.dispReverse() ); // Grape
374 | // Pear
375 | // Banana
376 | // Apple
377 | ```
378 |
379 |
380 |
381 | ## 循环链表
382 |
383 | 循环链表和单链表相似,节点类型都是一样,唯一的区别是,在创建循环链表的时候,让其头节点的 next 属性执行它本身,即
384 | ```js
385 | head.next = head;
386 | ```
387 |
388 | 这种行为会导致链表中每个节点的 next 属性都指向链表的头节点,换句话说,也就是链表的尾节点指向了头节点,形成了一个循环链表,如下图所示:
389 |
390 |
391 |
392 | 原理相信你已经懂了,循环链表这里就不贴代码了,相信你自己能独立完成!
393 |
394 | 至此,我们对链表有了比较深刻的认识,如果想让我们的链表更加健全,我们还可发挥自己的思维,给链表添加比如向前移动几个节点,向后移动几个节点,显示当前节点等方法,大家一起加油!
395 |
396 |
397 | # 参考文档
398 |
399 | - [JS中的算法与数据结构——链表(Linked-list)](https://www.jianshu.com/p/f254ec665e57)
--------------------------------------------------------------------------------