第一节:邂逅数据结构和算法、线性结构、数组、栈详解
一. 邂逅数据结构和算法
1. 编程的最终目的
所有的编程最终的目的都是为了处理数据
2. 什么是数据结构
数据结构是存储和组织数据的方式,常用的数据结构有:数组、链表、栈、队列、树、图。
3. 什么是算法
算法是解决问题的办法、逻辑步骤。
二. 线性结构-数组
1. 什么是线性结构
(1) 是由n(n≥0)个数据元素(结点)a[0],a[1],a[2]…,a[n-1]组成的有限序列。
◼ 其中:
数据元素的个数n定义为表的长度 = “list”.length() (“list”.length() = 0(表里没有一个元素)时称为空表)。
将非空的线性表(n>=1)记作:(a[0],a[1],a[2],…,a[n-1])。
数据元素a[i](0≤i≤n-1)只是个抽象符号,其具体含义在不同情况下可以不同
(2). 常见的线性结构有:数组、栈、队列、链表。
2. 数组
(1). 数组是一种线性的结构,基本上每种编程语言中都有数组,我们可以基于数组来实现:栈、队列、堆。
(2). 数组在内存中是连续的,所以当知道数组的下标的时候,访问效率非常快。
(3). 数组可以在任何位置进行 插入、删除数据。
如下图:
三. 栈详解
1. 什么是栈
(1). 栈是一种受限的线性结构,后进先出(LIFO)。
(2) 其限制是仅允许在 表的一端 进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。
(3) LIFO(last in first out)表示就是后进入的元素, 第一个弹出栈空间。 类似于自动餐托盘, 最后放上的托盘, 往往先把拿出去使用。
(4) 向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;
(5) 从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素
2. 面试题1-栈结构
有六个元素6,5,4,3,2,1 的顺序进栈,问下列哪一个不是合法的出栈序列?()
A. 543612 B. 453216 C. 346521 D. 234156
查看代码
答案:C
解决该问题的关键的是可以先进栈3个,然后出栈2个,然后再进栈1个,依次类推。
A 65进栈,5出栈,4进栈,4出栈,3进栈,3出栈,6出栈,21进栈,12出栈
B 654进栈,45出栈,3进栈,3出栈,2进栈,2出栈,1进栈,1出栈,6出栈
C 6543进栈,34出栈,此时6无法出栈,所以 C错误。
D 65432进栈,234出栈,1进栈,1出栈,56出栈
3. 基于数组实现栈
(1). 首先需要先了解数组常用的几个方法
pop: 在数组的最后位置删除一个元素,并返回该元素
push: 在数组最后位置插入一个元素
unshift:删除数组第一个元素,并返回该元素
shift:在数组最开始的位置插入一个元素
(2). 栈常用的方法
push: 向栈顶添加元素
pop:移除栈顶元素,同时返回该移除的元素
peek: 返回栈顶元素,不做任何操作
isEmpty:判断栈中是否存在元素,存在 true,反之 false
size:栈中元素的个数
(3). 普通栈的实现
查看代码
class MyStack {
//底层存储数据
private myArray: any[] = []; //任意类型的数组
push(item: any): void {
this.myArray.push(item);
}
pop(): any {
return this.myArray?.pop();
}
peek(): any {
return this.myArray[this.myArray.length - 1];
}
isEmpty(): boolean {
return this.myArray.length === 0;
}
size(): number {
return this.myArray.length;
}
}
// 测试
let stack = new MyStack();
stack.push("1");
stack.push(2);
stack.push("3");
stack.push(5);
console.log(stack.size());
console.log(stack.isEmpty());
console.log(stack.peek());
//出栈
let str: string = "";
while (stack.size() > 0) {
str += stack.pop();
}
console.log(str);
export default MyStack;
(4) . 抽离接口和利用泛型重构栈
查看代码
/**
* 抽离栈的接口
*/
interface IStack<T> {
//入栈
push(item: T): void;
// 出栈
pop(): T | undefined;
// 返回栈顶元素
peek(): T | undefined;
// 判断是否为空
isEmpty(): boolean;
// 栈中元素个数
size(): number;
}
export default IStack;
import IStack from "./IStack";
/**
* 引入泛型 和 接口,来重构栈
*/
class MyStack<T> implements IStack<T> {
//底层数据结构-数组
private array: T[] = [];
//入栈
push(item: T): void {
this.array.push(item);
}
//出栈,并返回出栈元素
pop(): T | undefined {
return this.array.pop();
}
// 返回栈顶元素,
peek(): T | undefined {
return this.array[this.array.length - 1];
}
//判断是否为空
isEmpty(): boolean {
return this.array.length === 0;
}
//返回栈元素的个数
size(): number {
return this.array.length;
}
}
4. 基于链表实现栈
后续补充
5. 面试题2-十进制转二进制
(1). 首先要知道数学方法
(2). 核心思路
/**
* 将十进制转换成二进制2
* @param num 十进制输入
* @returns 返回二进制
*
* 核心思路:十进制除2取余数,然后将余数从下往上排起来,就是二进制,利用栈后进先出的特性,将
* 余数存放到栈中,然后再取出来,正好就是这个二进制的数。
*
* 优化代码:直接使用参数中的num,作为被除数一直来赋值即可,可以省略之前的result参数
*
*/
function decimalToBinary2(num: number): string {
let stack = new MyStack<number>();
while (num > 0) {
let yushu = num % 2; //余数
stack.push(yushu);
num = Math.floor(num / 2); //下一次的被除数 【向下取整】
}
//出栈拼接
// while: 不确定次数, 只知道循环结束跳转
// for: 知道循环的次数时
let str = "";
while (stack.size() > 0) {
str += stack.pop();
}
return str;
}
console.log("--------------------decimalToBinary2-------------------------");
console.log(decimalToBinary2(35));
console.log(decimalToBinary2(50));
console.log(decimalToBinary2(71));
6. 面试题3-有效的括号
leetcode:https://leetcode.cn/problems/valid-parentheses/description/
代码实现
/**
* 判断输入的str是否是有效括号
* @param str 括号字符串
* @returns true 或 false
* 问题说明:
* 总共有三类括号:()、[]、{}, ① 每个左侧的括号必须直接跟着一个相同的右侧括号 或者 ② 一个括号整体包裹另外一个括号 ({})
* 只有上述两种括号是合格的。
* 解题思路
* (1). 依次遍历,如果是左侧括号,则把右侧括号放入栈中
* (2). 如果是右侧括号,则出栈数据,进行比较,相同则有效,不相同则无效
*/
function isValid(str: string): boolean {
let stack = new MyStack<string>();
for (let i = 0; i < str.length; i++) {
const element = str[i];
switch (element) {
case "(":
stack.push(")");
break;
case "{":
stack.push("}");
break;
case "[":
stack.push("]");
break;
default:
//表示是右侧括号,则和出栈的数据进行比较
if (element !== stack.pop()) {
return false;
}
break;
}
}
return stack.size() === 0; //解决这种情况 ([]){}{
}
console.log(isValid("()"));
console.log(isValid("([]){}"));
console.log(isValid("(]"));
console.log(isValid("([]){}{"));
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。