上篇数据结构那些事(一)已经介绍了数组,列表和栈。这篇咱们将介绍队列,链表,字典。数组
队列的两种主要操做是:向队列中插入新元素和删除队列中的元素。入队操做在队尾插入新元素,出队在队头删除元素。 接下来,咱们来设计一个队列Queue类:bash
function Queue(){
this.dataStore = [];//存储
this.enqueue = enqueue;//入队
this.dequeue = dequeue;//出队
this.front = front;//队首
this.back = back;//队尾
this.toString = toString;//显示队列元素
this.empty = empty;//清除
}
复制代码
实现上面的操做方法:cookie
function enqueue(e){
this.dataStore.push(e);
}
function dequeue(e){
this.dataStore.shift(e)
}
function front(){
return this.dataStore[0]
}
function back(){
return this.dataStore[this.dataStore.length - 1]
}
function toString(){
let retStr = "";
for (let i = 0; i<this.dataStore.length; ++i){
retStr += this.dataStore[i] + "\n";
}
return retStr;
}
function empty(){
if(this.dataStore.length === 0){
return true;
}else{
return false;
}
}
复制代码
上面咱们实现了一个基础的队列。但现实生活中,可能会出现相似军人优先,重病患优先这样的场景,那样咱们上面的队列就没法知足了。这时,咱们须要一个优先队列。 从优先队列中删除元素时,须要考虑优先权的限制。咱们来定义一下存储在队列中的元素:数据结构
function Person(name, code){
this.name = name;
this.code = code; //表示优先级,越小优先级越高
}
复制代码
如今,须要从新定义dequeue()方法。post
function dequeue(){
let p = this.dataStore[0].code;
for(let i =1 ; i < this.dataStore.length; ++i){
if(this.dataStore[i].code < p){
p = i
}
}
return this.dataStore.splice(p, 1);
}
复制代码
链表元素依靠相互之间的关系进行引用。遍历链表,就是跟着链表,从链表的首元素一直走到尾元素,链表的尾元素通常指向null。ui
下图演示了在eggs后插入cookies操做this
咱们设计的链表包含两个类。Node类用来表示节点,LinkedList类提供插入,删除,显示元素等方法。spa
function Node(e){
this.element = e;
this.next = null;
}
function LList(){
this.head = new Node("head");
this.find = find; //遍历链表,查找给定数据
this.findPrev = findPrev; //遍历链表,查找给定数据前面一个节点
this.insert = insert; //插入一个节点
this.remove = remove; //删除
this.display = display; //显示
}
复制代码
实现上面的方法:设计
function find(e){
let currNode = this.head;
while(currNode.element !== e){
currNode = currNode.next;
}
return currNode;
}
function insert(newEl, e){
let newNode = new Node(newEl);
let current = this.find(e);
newNode.next = current.next;
current.next = newNode;
}
function display(){
let currNode = this.head;
while(currNode.next !== null){
console.log(currNode.next.element);
corrNode = currNode.next;
}
}
function findPrev(e){
let currNode = this.head;
while(currNode.next !== null && currNode.next.element !== e){
currNode = currNode.next;
}
return currNode;
}
function remove(e){
let prev = this.findPrev(e);
if(prev.next !== null){
prev.next = prev.next.next;
}
}
复制代码
这时,咱们能够考虑实现一个双向链表:code
function Node(element) {
this.element = element;
this.next = null;
this.previous = null;
}
复制代码
咱们还要修改对应的insert方法,由于他如今须要创建两个链接
function insert(newElement, item) {
var newNode = new Node(newElement);
var current = this.find(item);
newNode.next = current.next;
newNode.previous = current;
current.next = newNode;
}
复制代码
双向链表的remove()方法比单向链表的效率更高,由于不须要查找前驱节点了。
function remove(item) {
var currNode = this.find(item);
if (!(currNode.next == null)) {
currNode.previous.next = currNode.next;
currNode.next.previous = currNode.previous;
currNode.next = null;
currNode.previous = null;
}
}
复制代码
function LList() {
this.head = new Node("head");
this.head.next = this.head; //让头结点的next指向它本身
this.find = find;
this.insert = insert;
this.display = display;
this.findPrevious = findPrevious;
this.remove = remove;
}
复制代码
JavaScript中的Object类就是以字典形式设计的。因此字典的实现就像对象同样,感受实在没什么值得写的,这里给一个demo。
function Dictionary(){
this.dataStore = new Array();
}
function add(key, value){
this.dataStore[key] = value;
}
function find(key){
return this.dataStore[key];
}
function remove(key){
delete this.dataStore[key]
}
function show(){
for( let key in Object.keys(this.dataStore)){
console.log(key + this.dataStore[key])
}
}
复制代码