第一节:邂逅数据结构和算法、线性结构、数组、栈详解

一. 邂逅数据结构和算法

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取余数,然后将余数从下往上排起来,就是二进制,利用栈后进先出的特性,将 余数存放到栈中,然后再取出来,正好就是这个二进制的数。
/**
 * 将十进制转换成二进制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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2023-11-06 13:57  Yaopengfei  阅读(42)  评论(1编辑  收藏  举报