数据结构与算法(一)

数据结构与算法(一)


什么是数据结构与算法?

  • 什么是数据结构和算法呢?
  • 可能你之前经常在很多地方都看到有人讨论数据结构和算法,但是它到底是什么一直云里雾里.
  • 因为似乎我们学习编程的过程中,没有必要了解这些,我只是在学习一门语言的基本语法/高级语法/做出界面效果/实现复杂的逻辑就可以了.
  • 数据结构和算法?它是什么? l don’t care?
  • 如果我们只是想了解语言的应用层面,那么数据结构和算法显得没有那么重要.口但是如果我们希望了解语言的设计层面,那么数据结构和算法就非常的重要.
  • 举个例子:
    Java的线性结构列表,有 ArrayList 和 LinkedList, 如果选择呢?
    :死记住规则,你也可以很好的选择,但是如果你了解它们底层的数据结构就会非常清晰的知道如何选择.

到底什么是数据结构与算法? 官方没有定义…

民间定义:

  • “数据结构是数据对象,以及存在于该对象的实例和组成实例的数据元素之间的各种联系。这些联系可以通过定义相关的函数来给出。”—《数据结构、算法与应用》
  • “数据结构是 ADT (抽象数据类型Abstract Data Type )的物理实现。”—《数据结构与算法分析》
  • “数据结构( data structure )是计算机中存储、组织数据的方式。通常情况下,精心选择的数据结构可以带来最优效率的算法。”—中文维基百科

我们还是从自己的角度来认识数据结构吧:

  • 数据结构就是在计算机中,存储和组织数据的方式
  • 我们知道,计算机中数据量非常庞大,如何以高效的方式组织和存储呢?
  • 这就好比一个庞大的图书馆中存放了大量的书籍,我们不仅仅要把书放进入,还应该在合适的时候能够取出来

常用的数据结构

队列(Queue)、树(Tree)、堆(Heap)、数组(ArrayList)、栈(Stack)、链表(Linked List)、图(Graph)、散列表(Hash)

  • 常见的数据结构较多
    • 每一种都有对应的应用场景,不同的数据结构不同的操作 性能是不同的。
    • 有的查询性能很快,有的插入速度很快,有的是插入头和尾的速度很快
    • 有的做范围查找很快,有的允许元素重复,有的不允许重复等等
    • 在开发中如何选择,要根据具体的需求来决定
  • 注意:数据结构与语言无关,常见的编程语言,直接或间接 的使用上述常见的数据结构
  • 为什么学习JavaScript没有接触过数据结构? 好像只见过数组
    • 单纯从 客户程序员 的角度,我们不需要过多的了解它们的实现细节
    • 但是简单的使用不能让我们更加灵活地使用他们,了解真相,你才能获得真正的自由!

什么是算法?

  • 算法(Algorithm)的认识

    • 在之前的学习中,我们可能学习过几种排序算法.并且知道,不同的算法,执行效率是不一样的.
    • 也就是说解决问题的过程中,不仅仅数据的存储方式会影响效率,算法的优劣也会影响着效率。
    • 那么到底什么是算法呢?
  • 算法的定义:

    • 一个有限指令集,没调指令的描述不依赖于语言
    • 接受一些输入(有些情况不需要输入)
    • 产生输出
    • 一定在有限步骤之后终止
  • 算法的通俗理解

    • Algorithm 这个单词本意就是解决问题的办法/步骤逻辑。
    • 数据结构的实现,离不开算法

数组结构

  • JavaScript的数组就是 API的调用:不讲
  • 普通其他语言的数组封装(比如Java的ArrayList)
    • 常见的语言的数组 不能 存放 不同的数据类型,因此所有的在封装时通常存放在数组中的是Object类型
    • 常见语言的数组容量不会自动改变(需要进行扩容操作)
    • 常见语言
    • 、’组进行中间插入和删除操作性能比较低

栈结构

  • 栈也是一种非常常见的数据结构,并且在程序中应用非常广泛。
  • 数组:
    • 我们知道数组是一种线性结构,并且可以在数组的任意位置插入和删除数组
    • 但是有时候,我们为了实现某些功能,必须对这种任意性加以限制
    • 而 栈和队列 就是比较常见的受限的线性结构,我们先来学习栈结构
  • 栈(stack)它是一种受限的线性表,后进先出(LIFO)
    • 其显示是仅允许在表的一端进行插入和删除运算,这一段被称为栈顶,相对的,把另一端成为栈底。
    • LIFO(Last In First Out)表示就是后进先出的的元素,第一个弹出栈空间。
    • 向一个栈插入新元素又被称作 进栈、入栈和压栈,它是把新元素放到栈顶元素的上面,是指成为新的栈顶元素;
    • 从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素
  • 程序中什么是使用栈实现的呢?
    • 函数调用栈
    • 我们知道函数之间的相互调用:A调用B,B调用C,C调用D;
    • 那样在执行的过程中,会将A压入栈,A没有执行完,所以不会弹出栈
    • 在A执行过程中调用了B,会将B压入到栈,这个时候B在栈顶,A在栈底。
    • 如果这个时候B可以执行完,那个B会弹出栈,但是B没有执行完,他调用了C
    • 所以C会压入栈,并且在栈顶,而C调用了D,D会压入到栈顶。
    • 所以当前栈循序是:栈顶 A -> B -> C -> D;
    • D执行完,弹出站 C-> B -> A 依次弹出栈。
    • 所以我们有函数调用栈的称呼,就来自与他们内部的实现机制,(通过栈来实现的)
      在这里插入图片描述
栈的面试题

在这里插入图片描述

答案:C

解析:并没有说是一次性全部入栈(一次性入栈只有一个答案:1 2 3 4 5 6)

A: 65进栈,5出栈,43进栈,43出栈,6出栈,2,1进栈,2出栈,1出栈

B: 654进栈,4出栈,5出栈,3进栈出栈,22进栈出栈,1进栈出栈,6出栈

D: 65432进栈,2出栈,3出栈,4出栈,1 进栈出栈,5出栈,6出栈

实现栈结构
  • 栈常见有哪些操作呢?
    • push(element): 添加一个新元素到栈顶位置
    • pop(): 移除栈顶的元素,同事返回被移除的元素
    • peek(): 返回栈顶的元素,不对栈做出任何修改(这个方法不会移除栈顶的元素,仅仅返回它)
    • isEmpty(): 如果栈里面没有任何元素返回 true, 否则返回 false
    • size() 返回栈里的元素个数,这个方法和数组的length 属性很类似
    • toString() :将栈结构的内容以字符形式返回
// 封装的栈类
function Stack() {
    // 栈中的属性
    this.item = [];

    // 栈中常见的操作
    // 1. 将元素压入栈
    Stack.prototype.push = function(element) {
        this.item.push(element);
    }
    // 2、从栈中取出元素
    Stack.prototype.pop = function() {
        return this.item.pop();
    }
    // 3、查看一下栈顶元素
    Stack.prototype.peek = function() {
        return this.item[this.item.length - 1];
    }
    // 4、判断栈是否为空
    Stack.prototype.isEmpty = function() {
        return this.item.length === 0;
    }
    // 5、获取栈中元素的个数
    Stack.prototype.size = function() {
        return this.item.length
    }
    // 6、toString 方法
    Stack.prototype.toString = function() {
        return this.item.join(',');
    }
}
let s = new Stack();
s.push(1)
s.push(2)
s.push(3)
s.push(4)
console.log(s.pop());
console.log(s.peek());
console.log(s.isEmpty());
console.log(s.size());
console.log(s.toString());
十进制转二进制
  • 为什么需要十进制转二进制?
    • 现实生活中,我们主要使用十进制。
    • 但在计算科学中,二进制非常重要,因为计算机里的所有内容
    • 都是用二进制数字表示的(0和1)。
    • 没有十进制和二进制相互转化的能力,与计算机交流就很困难。
  • 如何实现十进制转二进制?
    • 要把十进制转化成二进制,我们可以将该十进制数字和2整除,(二进制是满二进一),直到结果是0为止
// 函数:十进制转二进制
function desc2Bin(descNumber) {
    // 1. 定义栈对象
    let stack = new Stack();
    // 2. 循环操作
    while (descNumber > 0) {
        // 2.1 获取玉树,并且压入栈
        stack.push(descNumber % 2);
        // 2.2 获取整除后的结果,作为下一次运行的数组
        descNumber = Math.floor(descNumber / 2);
    }
    // 3. 从栈中去除 0 和 1
    let fooBin = '';
    while (!stack.isEmpty()) {
        fooBin += stack.pop()
    }
    return fooBin;
}
// 测试 十进制转二进制的函数
console.log(desc2Bin(100));
console.log(desc2Bin(1000));

队列结构

  • 受限的线性结构

    • 我们已经学习了一种 受限的线性结构:栈结构
    • 并且知道这种受限的数据结构对于某些特定问题会有特定效果
  • 队列(Queue),它是一种受限的线性表,先进先出(FIFO First in First Out)

    • 受限之处在于它只允许再表的前端(front) 进行删除操作
    • 而在表的后端(rear) 进行插入操作
  • 打印队列:

    • 有五份文档需要打印,这些文档会按照顺序放入到打印队列中
    • 打印机会一次从队列中去除文档,优先放入的文档,优先被去除,并且对该文档进行打印
    • 以此类推,知道队列中不在有新的文档
  • 线程队列:

    • 在开发中,为了让任务可以并行处理,通常会开启多个线程
    • 但是,我们不能让大量的线程同时运行处理任务(占用过多的资源)
    • 这个时候,如果有需要开启线程处理任务的情况,我们就会使用线程队列
    • 线程队列会依照依序来启动线程,并且处理对应的任务。
      在这里插入图片描述
如何实现队列?
  • 队列的实现和栈一样,有两种方案

    • 基于数组实现
    • 基于链表实现
  • 基于数组实现

  • 队列有哪些常见的操作呢?

    • enqueue(element):向队列尾部添加一个(或多个)新的项。
    • dequeue()∶移除队列的第一(即排在队列最前面的)项,并返回被移除的元素。
    • front():返回队列中第一个元素——最先被添加,也将是最先被移除的元素。队列不做任何变动(不移除元素只返回元素信息——与Stack类的peek方法非常类似)。
    • isEmpty():如果队列中不包含任何元素,返回true,否则返回false。size():返回队列包含的元素个数,与数组的length属性类似。
    • toString():将队列中的内容,转成字符串形式
    • size() : 返回队列包含的元素
  •  // 封装队列
    function Queue() {
        // 属性
        this.item = [];
        // 方法
        Queue.prototype.enqueue = function(element) {
            this.item.push(element)
        }
        Queue.prototype.dequeue = function() {
            this.item.shift();
        }
        Queue.prototype.front = function() {
            return this.item[0]
        }
        Queue.prototype.isEmpty = function () {
            return this.item.length === 0
        }
        Queue.prototype.size = function () {
            return this.item.length
        }
        Queue.prototype.toString = function (partition) {
            return this.item.join(partition || '');
        }
    }
    
    // 使用
    let queue = new Queue();
    queue.enqueue(11)
    queue.enqueue(22)
    queue.enqueue(33)
    queue.dequeue();
    console.log(queue.size());
    console.log(queue.isEmpty());
    console.log(queue.front());
    console.log(queue.toString(','));
    
队列面试题(击鼓传花)
// 面试题:击鼓传花
function passGame(nameList, number) {
    // 创建一个队列
    let queue = new Queue();
    // 将所有人放入队列
    nameList.forEach(element => {
        queue.enqueue(element)
    })
    // 开始数数字
    while (queue.size() > 1) {
        // 不是 num 的时候,重新加入到队列的末尾
        // 是 num 这个数字的时候,将其从队列中删除
        for (let i = 0; i < number - 1; i++) {
            queue.enqueue(queue.dequeue())
        }
        // num对应的这个人,直接从队列中删除
        queue.dequeue();
    }
    // 获取剩下的人
    return queue.front()
}

const names = [ 'Rookie', '姜晨露', '刘美丽']

console.log(passGame(names, 10));

待更新…

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值