一、栈的封装
栈:先进后出
// method方法 和某个对象实例有联系
function Stack() {
this.items = [] //栈中的属性
// 压入栈
// this.push = function() { //方法
// }
Stack.prototype.push = function (element) {
this.items.push(element)
}
// 取出元素
Stack.prototype.pop = function () {
return this.items.pop()
}
// 查看元素
Stack.prototype.peek = function () {
return this.items[this.length - 1]
}
// 判断栈是否为空
Stack.prototype.isEmpty = function () {
return this.items.length == 0
}
// 获取栈中元素的个数
Stack.prototype.size = function () {
return this.items.length
}
// toString方法
Stack.prototype.toString = function () {
for (var i = 0; i < this.items.length; i++) {
resultString += this.items[i] + ''
}
return resultString
}
}
// var s = new Stack()
// s.push(22)
// console.log(s.isEmpty());
function decbin2(decNumber) {
var stack = new Stack()
while(decNumber > 0) {
stack.push(decNumber % 2)
decNumber = Math.floor(decNumber / 2)
}
var binaryString = ''
while(!stack.isEmpty()) {
binaryString += stack.pop()
}
return binaryString
}
alert(decbin2(100))
二、队列的封装
先进先出
function Queue() {
this.items = []
// 加入队列
Queue.prototype.enqueue = function (element) {
this.items.push(element)
}
// 删除前端口元素
Queue.prototype.dequeue = function () {
return this.items.shift()
}
// 查看前端的元素
Queue.prototype.front = function () {
return this.items[0]
}
// 查看队列中元素是否为空
Queue.prototype.isEmpty = function () {
return this.items.length == 0
}
// 查看队列中元素的个数
Queue.prototype.size = function () {
return this.items.length
}
// toString方法
Queue.prototype.toString = function () {
var resultString = ''
for (let i = 0; i < this.items.length; i++) {
resultString += this.items[i] + ' '
}
return resultString
}
}
// var Queue = new Queue()
// Queue.enqueue('acb')
// Queue.enqueue('sdf')
// Queue.enqueue('edc')
// alert(Queue)
// Queue.dequeue()
// alert(Queue.front())
// alert(Queue.isEmpty())
// alert(Queue.toString())
// 队列应用之击鼓传花
function flower(nameList, num) {
var queue = new Queue()
// 将所有人一次加入队列
for (var i = 0; i < nameList.length; i++) {
queue.enqueue(nameList[i])
}
// 开始数数字
while (queue.size() > 1) {
for (var i = 0; i < num - 1; i++) {
queue.enqueue(queue.dequeue())
}
queue.dequeue()
}
// 获取最后剩下的那个人
alert(queue.size()) // kankan最后是不是队列是不是只有一个元素
console.log(queue.front());
var endName = queue.front()
alert('最后一个人是: ' + endName)
return nameList.indexOf(endName)
}
names = ['lili', 'haha', 'xixi', 'leilei']
alert(flower(names, 3))
三、优先级队列的封装
function PriortyQueue() {
// 类新创建一个类 可理解成内部内
function QueueElement(element, priorty) {
this.element = element
this.priorty = priorty
}
this.items = [] //封装属性
PriortyQueue.prototype.enqueue = function (element, priorty) {
var queueElement = new QueueElement(element, priorty)
// 判断队列是否为空
if (this.items.length == 0) {
this.items.push(queueElement)
} else {
var added = false
for (var i = 0; i < this.items.length; i++) {
if (queueElement.priorty < this.items[i].priorty) {
this.items.splice(i, 0, queueElement)
added = true
break
}
}
if (!added) {
this.items.push(queueElement)
}
}
}
// 删除前端口元素
PriortyQueue.prototype.dequeue = function () {
return this.items.shift()
}
// 查看前端的元素
PriortyQueue.prototype.front = function () {
return this.items[0]
}
// 查看队列中元素是否为空
PriortyQueue.prototype.isEmpty = function () {
return this.items.length == 0
}
// 查看队列中元素的个数
PriortyQueue.prototype.size = function () {
return this.items.length
}
// toString方法
PriortyQueue.prototype.toString = function () {
var resultString = ''
for (let i = 0; i < this.items.length; i++) {
resultString += this.items[i].element + this.items[i].priorty + ''
}
return resultString
}
}
var pq = new PriortyQueue()
pq.enqueue('abc', 1)
pq.enqueue('wsx', 2)
pq.enqueue('qqq', 1000)
pq.enqueue('edc', 3)
alert(pq)
四、链表的封装
//单向链表
function LinkedList() {
//结点类
function Node(data) {
this.data = data
this.next = null
}
this.head = null
this.length = 0 //计算链表的长度
// 1. 添加
LinkedList.prototype.append = function (data) {
var newNode = new Node(data) //新建新的结点
if (this.length == 0) {
this.head = newNode
} else {
var current = this.head
while (current.next) {
current = current.next
}
current.next = newNode // 最后结点的next指向新的结点
}
this.length += 1
}
// 2.toString
LinkedList.prototype.toString = function () {
var current = this.head
var listString = ''
while (current) {
listString += current.data + " "
current = current.next
}
return listString
}
// 3.insert
LinkedList.prototype.insert = function (position, data) {
// 对position进行边界判断
if (position < 0 || position > this.length) return false
var newNode = new Node(data)
if (position == 0) {
newNode.next = this.head
this.head = newNode
} else {
var index = 0
var current = this.head
var previous = null
while (index++ < position) {
previous = current
current = current.next
}
newNode.next = current
previous.next = newNode
}
this.length += 1
return true
}
// 4.get 获取对应位置
LinkedList.prototype.get = function (position) {
if (position < 0 || position >= this.length) return null
var current = this.head
var index = 0
while (index <= position) {
current = current.next
index++
}
return current.data
}
// 5.indexOf返回该元素在该链表中的索引
LinkedList.prototype.indexOf = function (data) {
var current = this.head
var index = 0
while(current) {
if(current.data == data) {
return index
}
current = current.next
index ++
}
return -1
}
// 6.update修改某一位置的数值
LinkedList.prototype.update = function (position, newData) {
if (position < 0 || position >= this.length) return null
var current = this.head
var index = 0
while(index++ < position) {
current = current.next
}
current.data = newData
return true
}
// 7.removeAt 从列表中移除一项
LinkedList.prototype.removeAt = function(position) {
if (position < 0 || position >= this.length) return null
if(position == 0) {
this.head = this.head.next
} else {
var current = this.head
var index = 0
var previous = null
while(index++ < position) {
previous = current
current = current.next
}
// 前一个结点的next指向current的next
previous.next = current.next
}
this.length -= 1
return current.data
}
// 8.remove
LinkedList.prototype.remove = function(data) {
//根据data获取位置
var position = this.indexOf(data)
//根据位置移除元素
return this.removeAt(position)
}
// 9.isEmpty
LinkedList.prototype.isEmpty = function () {
return this.length==0
}
// 10.size
LinkedList.prototype.size = function () {
return this.length
}
}
var list = new LinkedList()
list.append('ddd')
list.append('bbbb')
list.append('ccc')
list.insert('1', 'wsx')
list.update('2','ooo')
list.removeAt(1)
alert(list)
alert(list.get(1))
alert(list.indexOf('ddd'))
alert(list.isEmpty())
alert(list.size())
五、双向链表的封装
function LinkedList() {
// 内部类
function Node(data) {
this.data = data
this.next = null
this.prev = null // 新添加的
}
this.head = null;
this.tail = null;
this.length = 0;
// 向链表尾部加一个
LinkedList.prototype.append = function (data) {
// 1.根据元素创建节点
var 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.length+1
this.length++
}
// 链表转化为字符串
LinkedList.prototype.toString = function () {
return this.forwardString();
}
// 向前遍历
LinkedList.prototype.forwardString = function () {
var current = this.head
var forwardStr = ""
while (current) {
forwardStr += "," + current.data
current = current.next
}
return forwardStr.slice(1)
}
// 向后遍历
LinkedList.prototype.reverseString = function () {
var current = this.tail
var reverseStr = ""
while (current) {
reverseStr += current.data + " "
current = current.prev
}
return reverseStr
}
// 插入
LinkedList.prototype.insert = function (position, data) {
if (position < 0 || position > this.length) return false;
var newNode = new Node(data);
if (this.length == 0) {
this.head = newNode;
this.tail = newNode;
} else {
if (position == 0) { // 插入到第一个结点
this.head.prev = newNode;
newNode.next = this.head;
this.head = newNode;
} else if (position == this.length) { // 插入最后一个结点
newNode.prev = this.tail;
this.tail.next = newNode;
this.tail = newNode;
} else {
var current = this.head;
var index = 0;
while (index < position) {
current = current.next
index++
}
newNode.next = current;
newNode.prev = current.prev;
current.prev.next = newNode;
current.prev = newNode;
}
}
this.length++
return true
}
// 获取对应位置的值
LinkedList.prototype.get = function (position) {
if (position < 0 || position >= this.length) return null
// 效率不高
// var current = this.head;
// var index = 0;
// while(index ++ < position) {
// current = current.next
// }
// return current.data
if (this.length / 2 > position) {
let current = this.head;
let index = 0;
while (index++ < position) {
current = current.next
}
return current.data
} else {
let current = this.tail;
let index = this.length - 1;
while (index-- > position) {
current = current.prev
}
return current.data
}
}
// 返回对应位置的索引
LinkedList.prototype.indexOf = function (data) {
var current = this.head;
var index = 0
while (current) {
if(current.data == data) {
return index
}
current = current.next;
index ++
}
return -1
}
// 更新元素
LinkedList.prototype.update = function (position, data) {
if(position < 0 || position >= this.length) return false;
var current = this.head;
var index = 0;
while (index++ < position) {
current = current.next
}
current.data = data
return true
}
// 从列表的特定位置移除一项
LinkedList.prototype.removeAt = function (position) {
if(position < 0 || position >= this.length) return false;
var current = this.head;
if(this.length == 1) {
this.head = null;
this.tail = null;
} else {
if (position == 0) {
this.head.next.prev = null;
this.head = this.head.next;
} else if (position == this.length - 1) {
current = this.tail;
this.tail.prev.next = null;
this.tail = this.tail.prev;
} else {
var index = 0;
while(index++ < position) {
current = current.next
}
current.prev.next = current.next
current.next.prev = current.prev
current.prev = null
}
}
this.length -= 1
return current.data
}
// 移除元素
LinkedList.prototype.remove = function (data) {
var index = this.indexOf(data)
return this.removeAt(index)
}
//是否为空
LinkedList.prototype.isEmpty = function() {
return this.length == 0
}
// 长度
LinkedList.prototype.size = function () {
return this.length
}
// 获取链表的第一个元素
LinkedList.prototype.getHead = function() {
return this.head.data
}
// 获取链表的最后一个元素
LinkedList.prototype.getTail = function() {
return this.tail.data
}
}
// 测试
var list = new LinkedList()
list.append("abc")
list.append("cba")
list.append("nba")
list.append("mba")
list.insert(2, "aaa")
// alert(list.reverseString())
// alert(list.forwardString())
// alert(list)
// alert(list.get(4))
// alert(list.indexOf('aaa'))
// alert(list.indexOf('111'))
// list.update(2, 'ccc')
// alert(list.removeAt(1))
// list.remove('aaa')
alert(list.isEmpty())
alert(list.size())
alert(list.getHead())
alert(list.getTail())
alert(list)
六、集合的封装
// 和数学中集合名词相似,但是属性中结合范围更大,允许元素重复
// 在计算机中,集合通常表示的结构的元素是不允许重复的
// 可以看做特殊的数组 特殊之处在于没有顺序(所以不能通过下标直接访问),也没有重复
// 就是ES6的Set1类
function Set1() {
// 属性
this.items = {}
// 方法
Set1.prototype.add = function (value) {
// 判断集合中是否包含该元素
if (this.has(value)) {
return false
}
this.items[value] = value
return true
}
Set1.prototype.has = function (value) {
return this.items.hasOwnProperty(value)
}
Set1.prototype.remove = function (value) {
if (!this.has(value)) {
return false
}
delete this.items[value]
return true
}
Set1.prototype.clear = function () {
this.items = {}
}
Set1.prototype.size = function () {
return Object.keys(this.items).length //妙a
}
Set1.prototype.values = function () {
return Object.values(this.items)
}
// 集合间的操作
// 并集
Set1.prototype.union = function (otherSet) {
// this集合对象A otherSet集合对象B
// 1.创建新的集合
var unionSet = new Set1()
// 2.将A集合中的所有元素添加到新集合中
var values = this.values()
for (var i = 0; i < values.length; i++) {
unionSet.add(values[i])
}
// 3.取出B集合中的元素,判断是否需要加到新集合
values = otherSet.values()
for(var i = 0; i < values.length; i++) {
unionSet.add(values[i])
}
return unionSet
}
// 交集
Set1.prototype.insertsection = function (otherSet) {
var insertsection = new Set1()
// 从A中取出一个元素,判断是否同时存在集合B中,存放人新集合中
var values = this.values()
for(var i = 0; i < values.length; i++) {
var item = values[i]
if(otherSet.has(item)) {
insertsection.add(item)
}
}
return insertsection
}
// 差集
Set1.prototype.difference = function (otherSet) {
var differenceSet = new Set1()
var values = this.values()
for(var i = 0; i < values.length; i++) {
var item = values[i]
console.log(item);
if (!otherSet.has(item)) {
differenceSet.add(item)
}
}
return differenceSet
}
// 子集
Set1.prototype.subSet = function (otherSet) {
var values = this.values()
for (var i = 0; i < values.length; i++) {
var item = values[i]
if(!otherSet.has(item)) {
return false
}
}
return true
}
}
var set1 = new Set1()
set1.add("1")
set1.add("1")
set1.add("2")
set1.add("aaaa")
set1.add('b')
set1.remove(1)
// alert(set1.size())
// alert(set1.values())
// alert(set1.size())
var setA = new Set1()
setA.add('abc')
setA.add('qaz')
setA.add('iop')
var setB = new Set1()
setB.add('qwe')
setB.add('rfv')
setB.add('iop')
var setC = new Set1()
setC.add('qwe')
setC.add('rfv')
setC.add('iop')
// alert(setA.union(setB).values())
// alert(setA.insertsection(setB).values())
// alert(setA.difference(setB).values())
alert(setA.subSet(setB))
alert(setC.subSet(setB))
七、字典
字典的主要特点是一一对应的关系,通过键值对进行保存;字典的可以是不可以重复的,而value可以重复,并且字典中的可以是无序的。
八、哈希表
数组进行插入删除操作时,效率比较低;数组进行查找操作的效率:如果是基于索引查找进行查找效率非常高,基于内容查找比较低。
哈希表通常基于数组进行实现的,可以非常快速的插入删除查找(时间复杂度接近O(1)),通常哈希表中是不允许重复的,不能放置相同的key,用于保存不同的元素单数。但是哈希表的数据是无序的,所以不能以一种固定的方式(如从小到大)来遍历数据。
通过哈希化的下标值依然可能重复,冲突不可避免,常见有链地址法(拉链法)、开放地址法两种方案。
- 链地址法解决冲突的办法是每个数组单元中存储的不再是单个数据,二十一个链条,这个链条常用的数据结构是数组或链表。
- 开放地址发主要的工作方式是寻找空白的单元格来添加重复的数据。