不同的书对数据结构有不同的定义,例如:
虽然定义有所差别但其实本质核心是不变的,都是在计算机中, 存储和组织数据的方式
常见的数据结构其实还蛮多的,大致有栈、队列、链表、集合、字典、树等等
每种结构都有自己的特点,有的查询速度很快,有的插入速度很快,有的做范围查找很快,反正每一种结构都是有自己的优势的,具体场景的使用需要具体的分析
算法通常是与数据结构联系在一起的,我们说到数据结构就会想到算法,不同的算法会影响同一件事的执行效率,所以算法越好,执行的速度就越快
那么什么是算法呢?算法就是
一个有限指令集, 每条指令的描述不依赖于语言
接受一些输入(有些情况下不需要输入)
产生输出
一定在有限步骤之后终止
数据结构的实现, 是离不开算法的
栈(stack),它是一种运算受限的线性表示,后进先出(LIFO)或者说先进后出
push(element)
: 添加一个新元素到栈顶位置pop()
:移除栈顶的元素,同时返回被移除的元素peek()
:返回栈顶的元素,不对栈做任何修改(这个方法不会移除栈顶的元素,仅仅返回它)isEmpty()
:如果栈里没有任何元素就返回true
,否则返回false
clear()
:移除栈里的所有元素size()
:返回栈里的元素个数,这个方法和数组的length
属性很类似接下来我们就来封装一下这些常用的方法吧
<script>
class Stack {
constructor() {
// 创建一个空数组,来存放添加的元素
this.item = []
}
// 1.向栈顶添加元素 数组的最后添加元素
push(ele) {
this.item.push(ele)
}
// 2.移除栈顶元素,返回栈顶元素(数组最后一个元素)
pop() {
let delnode = this.item.pop();
return delnode
}
// 3.返回栈顶元素(数组最后一个元素)
peek() {
let index = this.item.length - 1;
return this.item[index]
}
// 4.判空 栈为空true 数组的length长度来判断栈是否为空
isEmpty() {
return this.item.length == 0;
}
// 5.清空栈
clear() {
this.item = [];
}
// 6.栈元素的个数 == 数组中元素的个数
size() {
return this.item.length
}
}
</script>
栈就封装好啦,需要用的时候直接使用script:src调用就好了
这里的代码量不算多,我也就没有去调用上面封装的方法,就直接自己写的
<script>
// 创建一个空数组,来装添加的内容
var arr = [];
// 传入需要转换的数和转换的进制
function change(chushu, base) {
// 为了符合十六进制的表示形式
let arr1 = ["A", "B", "C", "D", "E", "F"];
while (chushu > 0) {
let yushu = chushu % base;
if (yushu > 9) {
arr.push(arr1[yushu - 10])
} else {
arr.push(yushu)
}
var chushu = Math.floor(chushu / base);
}
var str = "";
while (!arr.length == 0) {
str += arr.pop();
}
return str;
}
console.log(change(100, 2));
console.log(change(10, 2));
console.log(change(10, 8));
console.log(change(30, 16));
</script>
大家可以自己去用计算检测一下转换的对不对
队列(Queue),和栈一样是一种运算受限的线性表,先进先出(FIFO First In First Out)或者后进后出
enqueue(element)
:向队列尾部添加一个(或多个)新的项dequeue()
:移除队列的第一(即排在队列最前面的)项,并返回被移除的元素front()
:返回队列中第一个元素——最先被添加,也将是最先被移除的元素。队列不做任何变动(不移除元素,只返回元素信息——与Stack
类的peek
方法非常类似)isEmpty()
:如果队列中不包含任何元素,返回true
,否则返回false
size()
:返回队列包含的元素个数,与数组的length
属性类似现在同样的我们来封装一下这些常用的方法
<script>
class Queue{
constructor(){
this.item = [];
}
// 1.入队
enqueue(ele){
this.item.push(ele)
}
// 2.出队
delqueue(){
return this.item.shift()
}
// 3.返回队首元素
front(){
return this.item[0]
}
// 4.判空
isEmpty(){
return this.item.length == 0
}
// 5.y元素的个数
size(){
return this.item.length
}
}
</script>
封装完成,使用的时候同栈的封装方法一样直接调用就可以了
来看一个实例叭
这个游戏规则是,给每个数据标号,标号为3的那个一个数据出栈了就不在进栈了,其余1,2的出栈了需要进栈,一直这样循环,直到队列里面只剩一个数据,那么这个数据就是最后的赢家,我们来看看代码吧
<script src="Queue.js"></script>
<script>
function jigu(arr) {
// 创建队列
let queue = new Queue();
// 依次入队
arr.forEach(ele => {
queue.enqueue(ele)
});
// 标号
let count = 1;
while (queue.size() > 1) {
if (count < 3) {
let node = queue.delqueue();
queue.enqueue(node);
count++;
} else {
queue.delqueue();
count = 1
}
}
// 获胜者和在原数组中的位置
return {
winner: queue.front(),
position: arr.indexOf(queue.front())
}
}
var arr = ["任嘉伦", "杨洋", "魏晨", "刘昊然", "戚薇", "张若昀", "黄蓉"];
console.log(jigu(arr));
</script>
上面介绍的一种是普通队列,还有一种比较特殊的队列,就是优先级队列
优先级队列的特点:
实现优先级队列相对队列主要有两方面需要考虑:
<script>
function PriorityQueue() {
var items = []
// 封装一个新的构造函数, 用于保存元素和元素的优先级
function QueueElement(element, priority) {
this.element = element
this.priority = priority
}
// 添加元素的方法
this.enqueue = function (element, priority) {
// 1.根据传入的元素, 创建新的QueueElement
var queueElement = new QueueElement(element, priority)
// 2.获取传入元素应该在正确的位置
if (this.isEmpty()) {
items.push(queueElement)
} else {
var added = false
for (var i = 0; i < items.length; i++) {
// 注意: 我们这里是数字越小, 优先级越高
if (queueElement.priority < items[i].priority) {
items.splice(i, 0, queueElement)
added = true
break
}
}
// 遍历完所有的元素, 优先级都大于新插入的元素时, 就插入到最后
if (!added) {
items.push(queueElement)
}
}
}
// 删除元素的方法
this.dequeue = function () {
return items.shift()
}
// 获取前端的元素
this.front = function () {
return items[0]
}
// 查看元素是否为空
this.isEmpty = function () {
return items.length == 0
}
// 获取元素的个数
this.size = function () {
return items.length
}
}
</script>
其实与普通队列相比也就多了几行确定优先级和位置的代码,其他的基本是一样