栈结构
我们可以把栈想象成一个竖着的量筒,最先放进去的东西,在最下面。(栈结构其实就是一个受限的线性结构)
所以栈的特点是:先入后出(在一头添加或者删除)。在生活中,还是比较常见的,比如我们去吃自助餐拿的那个餐盘,我们取到的餐盘是最后放上去的,而最先放的餐盘在最下面。
在程序中,栈是怎么应用的呢?比如函数调用函数
A调用B,B中调用C,C中调用D
此时,可以看作A在栈底,然后是B、C、D
D结束,C才会结束,B才会结束,A才会结束。
栈结构的小测试
有六个元素,6,5,4,3,2,1的顺序进栈,下列哪一个不合法序列
A:5,4,3,6,1,2
B:4,5,3,2,1,6
C:3,4,6,5,2,1
D:2,3,4,1,5,6
答案:C
(走一下就知道了)
使用数组实现栈
// 方法和某一个对象的实例有联系,把函数称为方法,正常就是函数
// 栈的封装
function Stack() {
this.items = [];
// 1.将元素加入到栈
Stack.prototype.push = function (element) {
this.items.push(element)
}
// 2.从栈中取出元素
Stack.prototype.pop = function () {
return this.items.pop()
}
// 3.查看栈顶元素
Stack.prototype.peek = function () {
return this.items[this.items.length - 1]
}
// 4.判断栈是否为空
Stack.prototype.isEmpty = function () {
return this.items.length == 0
}
// 5.获取栈中元素的个数
Stack.prototype.size = function () {
return this.items.length;
}
// 6.内容以字符串返回
Stack.prototype.toString = function () {
let resultString = ''
for (let i = 0; i < this.items.length; i++) {
resultString += this.items[i] + ''
}
return resultString;
}
}
// 栈的使用
let stack1 = new Stack();
stack1.push(20)
stack1.push(10)
stack1.push(10)
stack1.push(7)
console.log(stack1)
console.log(stack1.pop())
console.log(stack1.peek())
console.log(stack1.size())
console.log(stack1.isEmpty())
console.log(stack1.toString())

封装十转化二函数
我们知道十进制转化二进制,就是和2整除,直到结果为0为之。(二进制是满2进1)比如100转化二进制过程如下:

// 函数:十进制转换二进制
function toBin(decNumber) {
// 1.定义一个栈对象
let stack = new Stack();
// 2.循环操作
while (decNumber > 0) {
//获取余数,放到栈
stack.push(decNumber % 2)
// 获取整除结果
decNumber = Math.floor(decNumber / 2)
}
//3.从栈中取出01
let binString = ''
while (!stack.isEmpty()) {
binString += stack.pop()
}
return binString
}
// 测试
console.log(toBin(100))

下面,我们用计算器检验一下结果是否正确

队列结构
我们可以把栈想象成一个横着的管道,最先放进去的东西,在管道的最头。(队列结构也是一个受限的线性结构)
所以队列的特点是:先入先出(在队列尾部添加,在队列顶部删除)。在生活中,还是比较常见的,比如我们去吃排队在电影院买票,我们先排队的永远是先被处理买票的。
在程序中,队列是怎么应用的呢?比如线程
有很多个线程,会依照次序来启动线程进行处理对应的任务。
使用数组实现队列
其实是不建议这种的,因为数组实现队列,性能没有链表实现队列要好,数组在头删除一个元素,后面的元素都要依次往前进,所以性能有点不好。
// 封装队列
function Queue() {
// 属性
this.items = [];
// 方法
// 1.加入元素
Queue.prototype.enqueue = function (element) {
this.items.push(element);
}
// 2.删除(数组从头删除,性能不高,因为删除一个,后面都会移动,链表性能会更高)
Queue.prototype.dequeue = function () {
return this.items.shift();
}
// 3.查看
Queue.prototype.front = function () {
return this.items[0]
}
// 4.查看是否为空
Queue.prototype.isEmpty = function () {
return this.items.length === 0
}
// 5.队列元素个数
Queue.prototype.size = function () {
return this.items.length
}
// 6.tostring
Queue.prototype.toString = function () {
let reselutString = '';
for (let i = 0; i < this.items.length; i++) {
reselutString += this.items[i] + ''
}
return reselutString;
}
}
// 队列的使用
let q = new Queue();
q.enqueue(300)
q.enqueue(200)
q.enqueue(400)
q.enqueue(33)
console.log(q)
console.log(q.dequeue())
console.log(q.front())
console.log(q.isEmpty())
console.log(q.size())
console.log(q.toString())

链表
跟数组类似,如果对于删除头的这种操作,链表的性能要高于数组,如果对于删除某个位置的元素,链表只能从头开始访问,无法通过下标直接访问,需要一个个去访问,这时候数组的性能要高于链表。
链表:每个元素由一个存储本身元素的节点和一个指向下一个元素的引用(指针)所组成。
链表在插入和删除时,它的时间复杂度为O(1),相对数组效率高很多。
比如一个火车,他由一个火车头和很多个车厢组成。这就很像链表。

封装链表
单向链表
//封装类
function linkList() {
//内部类
function Node(data, next) {
this.data = data;
this.next = null;
}
// 属性
this.head = null;
this.length = 0;
// 1.追加方法
linkList.prototype.append = function (data) {
// 创建新节点
let newNode = new Node(data);
// 判断是否添加的是第一个节点
if (this.length === 0) {
this.head = newNode;
} else { //不是第一个节点
// 找到最后一个节点
let current = this.head;
while (current.next) {
current = current.next;
}
// 让最后节点的next指向新的节点
current.next = newNode;
}
this.length += 1;
}
// 2.tostring方法
linkList.prototype.toString = function () {
let current = this.head;
let listString = '';
// 循环获取一个个的节点
while (current) {
listString += current.data + ' ';
current = current.next;
}
return listString;
}
// 3.insert方法
linkList.prototype.insert = function (position, data) {
// 对position进行越界判断,不能负数
// 长度判断,不能超过链表本身的长度
if (position < 0 || position > this.length) return false;
// 先创建节点
let newNode = new Node(data);
if (position === 0) {
newNode.next = this.head;
this.head = newNode;
} else {
let index = 0;
let current = this.head;
let previous = null;
// index++ 先判断,在++
while (index++ < position) {
previous = current;
current = current.next;
}
newNode.next = current;
previous.next = newNode;
}
this.length += 1;
return true;
}
//4.get方法
linkList.prototype.get = function (position) {
if (position < 0 || position >= this.length) return null;
// 2.获取对应的数据
let current = this.head
let index = 0;
while (index++ < position) {
current = current.next;
// index++;
}
return current.data
}
// 5.indexOf
linkList.prototype.indexOf = function (data) {
let current = this.head;
let index = 0;
// 开始查找
while (current) {
if (current.data == data) {
return index;
}
current = current.next;
index += 1;
}
// 找到最后没有找到
return -1;
}
// 6.updata
linkList.prototype.update = function (position, data) {
if (position < 0 || position >= this.length) return false;
// 查找正确的节点
let current = this.head;
let index = 0;
while (index++ < position) {
current = current.next
}
// 将data修改
current.data = data;
return true;
}
// 7.remove(data)
linkList.prototype.remove = function (data) {
// 1.根据data获取data的位置
let position = this.indexOf(data)
// 2.根据位置信息删除节点
return this.removeAt(position);
}
// 8.removeAt(position)
linkList.prototype.removeAt = function (position) {
if (position < 0 || position >= this.length) return false;
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;
}
previous.next = current.next;
}
this.length -= 1;
return true;
}
}
let l = new linkList();

被折叠的 条评论
为什么被折叠?



