数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作。算法是为求解一个问题需要遵循的、被清楚指定的简单指令的集合。
下面是我总结整理出的关于数据结构与算法的相关内容,如有错误,欢迎交流。本文中对于方法的封装均采用JavaScript语言来实现。
一、数组
JavaScript中已经对数组有了一个非常完善的封装,所以js的数组就是API的调用。此处就不再重复讲了。
补充其他语言里面数组的封装:
(1)常见语言(如Java)的数组不能存放不同类型的数据元素,因此所有在封装时存放在数组里的时Object类型;
(2)常见语言的数组容量不会自动改变(需要进行扩容处理);
(3)中间插入和操作性能低。
使用数组的优点:通过下标值取元素和修改元素的效率特别高
二、栈结构(stack)
栈是一种常见受限的线性结构,其限制性在于访问、插入和删除元素只能在一端进行,这一端被称为栈顶,相对地,另一端被称为栈底。
LIFO(last in first out):表示后进入的元素,第一个弹出栈空间。类似于一挪盘子的使用,总是后放上去的先被使用。
向一个栈插入一个新元素又称作进栈、入栈或压栈(push),它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素。
从一个栈删除元素又称作出栈或退栈(pop),它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
下面来看一道经典面试题:
正确答案是C:
A答案:65进栈,5出栈,4进栈出栈,3进栈出站,6出栈,21进栈,1出栈,2出栈
B答案:654进栈,4出栈,5出栈,3进栈出栈,2进栈出栈,1进栈出栈,6出栈
D答案:65432建或者拿,2出栈,3出栈,4出栈,1进栈出栈,5出栈,6出栈
- 栈的封装及常见操作:
- 封装栈类:
function Stack(){
//栈中的属性
this.items=[];
//栈的相关操作
//栈的使用
var s=new Stack();
}
- 元素入栈的方法(push):
Stack.prototype.push=function(element){
this.items.push(element);
};
- 元素出栈(pop)的方法:
Stack.prototype.pop=function(){
return this.items.pop();
};
- 查看栈顶元素:
Stack.prototype.peek=function(){
return this.items[this.items.length-1];
};
- 判断栈是否为空:
Stack.prototype.isEmpty=function(){
return this.items.length==0;
};
- 获取栈中元素的个数:
Stack.prototype.size=function(){
return this.items.length;
};
- toString方法:
Stack.prototype.toString=function(){
var resultString='';
for(var i=0;i<this.items.length;i++){
resultString+=this.items[i]+'';
}
return resultString;
};
栈的应用:十进制数转二进制
function decTobin(number){
var stack=new Stack(); //定义栈对象
while(number>0){ //循环操作
//获取余数并压入栈中
stack.push(number%2);
//获取整除后的结果,作为下一次的运行数字
number=Math.floor(number/2);
}
//从栈中取出0和1
var binnum='';
while(!stack.isEmpty()){
binnum+=stack.pop();
}
return binnum;
}
三、队列结构(queue)
队列也是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,进行插入操作的端称为队尾,进行删除操作的端称为队头。
队列的常见操作与栈的操作类似,不同处在于入队列是enqueue,出队列是dequeue方法,查看队列中第一个元素时front方法。其方法的封装与栈类似,注意队列的特点是FIFO就可以了,此处不再赘述。
- 队列的应用:击鼓传花游戏的实现
游戏规则:几个人围成一圈玩一个游戏,开始数数,数到某个数字的人自动淘汰,最后剩下的人获胜。
function passFlower(nameList,num){
//1.创建一个队列结构
var queue=new Queue();
//2.将所有人加入到队列里面
for(var i=0;i<nameList.length;i++){
queue.enqueue(nameList[i]);
}
//3.开始数数
while(queue.size()>1) {
//3.1不是num的人,重新加入到队列的末尾位置
for (var k = 0; k < num-1; k++) {
queue.enqueue(queue.dequeue());
}
//3.2num对应的人,直接从队列中删除
queue.dequeue();
}
//4.获取剩下的那个人
var endname=queue.front();
console.log("最后的赢家是:"+endname);
return nameList.indexOf(endname)
}
队列中还有一个特殊的优先级队列,它不遵从先进先出(FIFO)的原则,在优先队列中,元素都被赋予优先级。当访问元素的时候,具有最高优先级的元素最先被删除。优先队列在生活中的应用还是比较多的,比如医院的急症室为病人赋予优先级,具有最高优先级的病人最先得到治疗。
四、链表结构
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列节点组成,这些节点不必在内存中相连。每个节点由数据部分Data和链部分Next,Next指向下一个节点,这样当添加或者删除时,只需要改变相关节点的Next的指向,效率很高。
单链表的结构示意: