栈、队列、链表
叶江怀 2017-04-28 数据结构
# 数据结构学习笔记
# 栈学习:
//栈:后进先出,后面进入栈中的数据要先取出才能操作之前进入栈中的数据
function Static(){
this.items = [];
//1、push():添加一个新元素到栈顶的位置
Static.prototype.push = function(element){
return this.items.push(element)
}
//2、pop():移除栈顶的元素,同时返回被移除的元素
Static.prototype.pop = function(){
return this.items.pop()
}
//3、peek():返回栈顶的元素,不对栈进行任何的修改(仅仅是查看栈顶元素,并返回这个
Static.prototype.peek = function(){
return this.items[this.items.length - 1]
}
//4、isEmpty():如果栈里没有任何元素,就会返回true,否则返回false
Static.prototype.isEmpty = function(){
return this.items.length === 0
}
//5、size():返回栈里的元素个数,这个方法和数组里的length属性很类似
Static.prototype.size = function(){
return this.items.length
}
//6、toString():将栈结构的内容以字符串的形式返回
Static.prototype.toString = function(){
let resultString =''
for(let i=0;i<this.items.length;i++){
resultString += this.items[i]+''
}
return resultString;
}
}
//js栈的操作:十进制转二进制(dec:十进制,bin:二进制)
function DecToBin(decNumber){
//1.定义栈对象
let stack = new Stack()
//2.递归
while (decNumber > 0){
//2.1 获取余数,并放到栈中
stack.push(decNumber % 2)
//2.2 获取整除后的结果,作为下一次的运行的数字
decNumber = Math.floor(decNumber / 2)
}
//3、从栈中去除0和1
let binaryString = ""
while(!stack.isEmpty()){
binaryString += stack.pop()
}
return binaryString
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 队列:先进先出:只允许后端加入数据前端删除数据(不是只前后端分离,是指队列的前端和后端)
(例如:排队买票,先买先离开队伍)
// 封装队列
function Queue() {
// 属性
this.items = []
// 方法
// 前两个方法体现了队列的先进先出的特性
// enqueue(element):向队列尾部添加一个或者多个项
Queue.prototype.enqueue=function (element) {
this.items.push(element)
}
// dequeue():移除第一个项,并返回这个元素
Queue.prototype.dequeue = function(){
return this.items.shift()
}
// front():返回队列中的第一个元素,也将是最先被移除的元素。队列不做任何变动(不移除元素,只返回元素信息--和Stack的peek()方法类似)
Queue.prototype.front = function(){
return this.items[0]
}
// isEmpty():如果队列中没有元素,则返回true,否则返回false
Queue.prototype.isEmpty = function(){
return this.items.length === 0
}
// size():返回队列中元素的个数
Queue.prototype.size = function(){
return this.items.length
}
// toString():将队列中的内容转为字符串的形式
Queue.prototype.toString = function(){
let resultString =''
for(let i=0;i<this.items.length;i++){
resultString += this.items[i]+''
}
return resultString;
}
}
//使用队列
let Queue = new Queue()
Queue.enqueue('abc');
Queue.enqueue('cba');
Queue.enqueue('nba');
alert(Queue)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 封装优先级队列:所谓的优先级队列就是指特定的值的优先级比较高
//封装队列
function PriorityQueue(){
//内部再次创建一个类,在内部使用
function QueueElement(element,priority){
this.ele = element;
this.pri = priority;
}
let items = []
PriorityQueue.prototype.enqueue = function(element,priority){
//1、创建QueueElement实例对象
let queueElemtnt = new QueueElement(elemet,priority)
if(this.items.length===0){
this.items.push(queueElement)
}else{
let isAdd = false
for(let i=0;i<this.items.lengtg;i++){
if(queueElemnt.pri<this.items[i].priority){
this.items.splice(i,0,queueElement)
isAdd = true
return;
}
}
if(!isAdd){
this.items.push(queueElement)
}
}
}
}
//测试队列
let priQueue = new PriorityQueue()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 击鼓传花算法:
游戏规则:就是你玩的击鼓传话的规则
修改成算法的规则:
1、几个朋友玩这个游戏,围成一圈,开始数数,数到某个数字的人自动淘汰
2、最后剩下的这个人将获得胜利,请问最后剩下的是原来那个位置上的人
封装一个基于队列的函数
1、参数,所有参与人的姓名,基于数字
2、最终剩下的一个人的名字
function Queue() {
// 属性
this.items = []
// 方法 :前两个方法体现了队列的先进先出的特性
// enqueue(element):向队列尾部添加一个或者多个项
Queue.prototype.enqueue=function (element) {
this.items.push(element)
}
// dequeue():移除第一个项,并返回这个元素
Queue.prototype.dequeue = function(){
return this.items.shift()
}
// front():返回队列中的第一个元素,也将是最先被移除的元素。队列不做任何变动(不移除元素,只返回元素信息--和Stack的peek()方法类似)
Queue.prototype.front = function(){
return this.items[0]
}
// isEmpty():如果队列中没有元素,则返回true,否则返回false
Queue.prototype.isEmpty = function(){
return this.items.length === 0
}
// size():返回队列中元素的个数
Queue.prototype.size = function(){
return this.items.length
}
// toString():将队列中的内容转为字符串的形式
Queue.prototype.toString = function(){
let resultString =''
for(let i=0;i<this.items.length;i++){
resultString += this.items[i]+''
}
return resultString;
}
}
//击鼓传花算法
function PassGame(nameList,num){
// 创建队列
let queue = new Queue()
// 将所有人加入队列中
for (let i = 0; i < nameList.length; i++) {
queue.enqueue(nameList[i])
}
// 开始数数字
// 不是num数字的时候重新加入队列的末尾
// 是num这个数字的时候,删除
// 循环:若size只剩下一个人时停止循环
while(queue.size() >1){
// 将不是num这个数字的人重新加入队列的末尾
for (let j = 0; j < num - 1; j++) {
queue.enqueue(queue.dequeue());
}
// 删除队列的第一个元素
queue.dequeue()
}
let endName = queue.front()
console.log('最后的人名:'+endName);
}
let names=["lilei","hanmeimei","madongmei","mashenmemei","madongshenme","shenme dongmei"]
this.PassGame(names,3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 链表学习:
function LinkedList() {
//内部节点类
function Node(data, next) {
this.data = data;
this.next = null;
}
//属性
let head = null;
this.length = 0; //链表长度
// append(element):向列表尾部添加一个新的项
LinkedList.prototype.append = function (ele) {
// 创建新节点
let newNode = new Node(ele);
//判断是否添加的是第一个节点
if (this.length === 0) {
this.head = newNode;
console.log(1);
} else {
// 让当前的current指向head,如果这个元素的next不为空就继续指向下一个元素的next,直到next为空
// 也就是找最后一个节点,因为最后一个节点的next为空
let current = this.head;
while (current.next) {
current = current.next;
}
// 然后向最后一个节点添加新的newNode
current.next = newNode;
console.log(2);
}
this.length += 1; //链长度加一
};
// insert(position,element):向列表的特定位置插入一个新的项
LinkedList.prototype.insert = function (position, ele) {
// 给position进行越界判断
// position不能为负数,不能超过链的长度
if (position < 0 || position > this.length) return false;
// 创建新节点
let newNode = new Node(ele);
// 判断插入位置是否为第一个节点
if (position === 0) {
newNode.next = this.head; //将原来第一个的节点指向当前newNode的next
this.head = newNode; //将head指向的下一个节点指向新的newNode的节点
} else {
let index = 0;
let previous = null;
let current = this.head;
while (index++ < position) {
previous = current;
current = current.next;
}
newNode.next = current;
previous.next = newNode;
}
this.length += 1;
return true;
};
// get(position):获取对应位置的元素
LinkedList.prototype.get = function (position) {
// 给position进行越界判断
// position不能为负数,不能超过链的长度
if (position < 0 || position >= this.length) return false;
// 获取对应的数据
let current = this.head;
let index = 0;
while (index < position) {
current = current.next;
index++;
}
return current.data;
};
// indexOf(element):返回元素在列表中的索引,如果列表中没有该元素则返回-1
LinkedList.prototype.indexOf = function (data) {
let current = this.head;
let index = 0;
while (current) {
if ((current.data = data)) {
return index;
}
index++;
current = current.next;
}
// 没有找到对应的时候,返回-1
return -1;
};
// update(position):修改某个位置的元素
LinkedList.prototype.update = function (position, newData) {
if (position < 0 || position >= this.length) return false;
let index = 0;
let current = this.head;
while (index < position) {
current = current.next;
index++;
}
current.data = newData;
};
// removeAt(position):从列表的特定位置移除一项
LinkedList.prototype.removeAt = function (position) {
if (position < 0 || position >= this.length) return null;
let current = this.head;
// 判断是否删除第一个节点
if (position === 0) {
this.head = this.head.next; //直接指向下一个节点即可
} else {
let index = 0;
let previous = null;
while (index < position) {
previous = current;
current = current.next;
index++;
}
previous.next = current.next;
this.length -= 1;
return current.data;
}
};
// remove(element):从列表中移除一项
LinkedList.prototype.remove = function (data) {
// 1、首先获取当前的位置
let position = this.indexOf(data);
// 2、其次将其删除
return this.removeAt(position);
};
// isEmpty():如果链表中不包含任何元素,则返回true,若是有元素就返回false
LinkedList.prototype.isEmpty = function () {
return this.length === 0;
};
// size():返回链表包含的元素个数,和数组的length一样
LinkedList.prototype.size = function () {
return this.length;
};
// toString():由于列表项使用Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值
LinkedList.prototype.toString = function () {
// 定义变量
let current = this.head;
let listString = "";
// 循环获取每个节点,并将其转为string
while (current) {
listString += current.data + "";
current = current.next;
}
return listString;
};
}
//测试代码
let list = new LinkedList();
list.append("abc ");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# 双向链表学习:
function DoublyLinkedList() {
// 创建内部节点
function Node(data) {
this.data = data;
this.next = null;
this.prev = null;
}
//创建属性
this.head = null;
this.tail = null;
this.length = 0;
// append(ele):向列表尾部添加一个新的项
DoublyLinkedList.prototype.append = function (data) {
// 1、根据data创建节点
let newNode = new Node(data);
// 2、判断添加的是否是第一个节点
if (this.length === 0) {
this.head = newNode;
this.tail = newNode;
} else {
newNode.prev = this.tail;
this.tail.next = newNode;
this.tail = newNode;
}
// 3、长度加一
this.length++;
};
// insert(position,ele):向列表的特定位置插入一个新的项
DoublyLinkedList.prototype.insert = function (position, ele) {
// 越界判断
if (position < 0 || position > this.length) return false;
// 创建节点
let newNode = new Node(ele);
// 判断原有的链表是否为空
if (this.length === 0) {
this.head = newNode;
this.tail = newNode;
} else {
// 判断是否position为0
if (position === 0) {
// 原来的节点向后移动一位,所以prev指向新的节点
this.head.prev = newNode;
// 新节点的下一位指向原来的节点
newNode.next = this.head;
// 现在的第一个的位置为新的节点
this.head = newNode;
} else if (position === this.length) {
// position为最后一个节点
newNode.prev = this.tail;
this.tail.next = newNode;
this.tail = newNode;
} else {
let current = this.head;
let index = 0;
while (index < position) {
current = current.next;
index++;
}
// 找到当前的current的节点后,修改指针
newNode.next = current;
newNode.prev = current.prev;
current.prev.next = newNode;
current.prev = newNode;
}
}
this.length++;
return true;
};
// get(position):获取对应位置的元素
DoublyLinkedList.prototype.get = function (position) {
if (position < 0 || position >= this.length) return null;
// 获取元素
let current = this.head;
let index = 0;
while (index < position) {
current = current.next;
index++;
}
return current.data;
};
// indexOf(ele):返回元素在列表中的索引。如果列表中没有该元素则返回-1
DoublyLinkedList.prototype.indexOf = function (ele) {
// 定义变量
let current = this.head;
let index = 0;
// 查找当前的节点
while (current) {
if (current.data === data) {
return index;
}
current = current.next;
index++;
}
return -1;
};
// update(position,ele):修改某个位置的元素
DoublyLinkedList.prototype.update = function (position, ele) {
// 判断越界
if (position < 0 || position >= this.length) return false;
// 寻找当前的节点
let current = this.head;
let index = 0;
while (index < position) {
current = current.next;
index++;
}
// 修改当前的数据
current.data = ele;
return true;
};
// removeAt(position):从列表中的特定位置移除一项
DoublyLinkedList.prototype.removeAt = function (position) {
// 判断越界
if (position < 0 || position >= this.length) return null;
// 判断是否只有一个节点
if (this.length === 0) {
//当只有一个节点时,删除该节点即head和tail都指向null
this.head = null;
this.tail = null;
} else {
if (position === 0) {
//判断是否删除的是第一个节点
this.head.next.prev = null; //删除第一个节点时,第二个节点的prev指向null
this.head = this.head.next; //head指向第二个节点
} else if ((position = this.length - 1)) {
//判断是否为最后一个节点
this.tail.prev.next = null; //如果是最后一个节点,此时的倒数第二个的next指向null
this.tail = this.tail.prev; //此时的tail指向倒数第二个---倒二变成现在倒一
} else {
// 定义变量
let index = 0;
let current = this.head;
// 找到当前的节点
while (index < position) {
current = current.next;
index++;
}
// 将当前节点的前一个节点的next指向现在节点的下一个,也就会跳过当前节点
current.prev.next = current.next;
// 将当前节点的下一个节点的prev指向现在节点的上一个,也就是跳过当前节点
current.next.prev = current.prev;
// 当跳过之后就会自动回收没有用到的节点
}
}
this.length -1
return current.data
};
// remove(ele):从列表中的特定位置移除一项
DoublyLinkedList.prototype.remove = function (ele) {
// 通过前面的indexof找到下标
let index = this.indexOf(ele);
// 通过下标删除该节点
return this.removeAt(index)
};
// isEmpty():如果链表中不包括任何元素就返回ture,否则返回false
DoublyLinkedList.prototype.isEmpty = function () {
return this.length === 0;
};
// size():返回链表中包含的元素个数
DoublyLinkedList.prototype.size = function () {
return this.length;
};
// toString():由于链表中使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值
DoublyLinkedList.prototype.toString = function () {
return this.backWardString();
};
// forWardString():返回正向遍历的节点字符串形式
DoublyLinkedList.prototype.forWardString = function () {
// 定义变量
let current = this.taillet;
let resultString = "";
// 依次向前遍历,获取每一个的节点
while (current) {
resultString += current.data + "";
current = current.prev;
}
return resultString;
};
// backWardString():返回反向遍历的节点字符串形式
DoublyLinkedList.prototype.backWardString = function () {
// 定义变量
let current = this.head;
let resultString = "";
// 依次向后遍历,获取每一个节点
while (current) {
resultString += current.data + "";
current = current.next;
}
return resultString;
};
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205