(五)数据结构之“链表”

链表是什么?

多个元素组成的列表
元素存储不连续,用next指针连在一起
在这里插入图片描述

数组 vs 链表

数组:增删非首尾元素是往往需要移动元素
链表:增删非首尾元素,不需要移动元素,只需要更改next的指向即可

JS中的链表

JavaScript中没有链表
可以用Object模拟链表

const a = { val: 'a' };
const b = { val: 'b' };
const c = { val: 'c' };
const d = { val: 'd' };
a.next = b;
b.next = c;
c.next = d;

// 遍历链表
let p = a;
while (p) {
    console.log(p.val);
    p = p.next;
}

// 插入
const e = { val: 'e' };
c.next = e;
e.next = d;

// 删除
c.next = d;

LeetCode:237.删除链表中的节点

在这里插入图片描述

解题思路
无法直接获取被删除节点的上个节点
将被删除节点转移到下个节点
解题步骤
将被删节点的值改为下个节点的值
删除下个节点
在这里插入图片描述
时间复杂度O(1),空间复杂度O(1)

LeetCode:206.反转链表

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

解题思路
反转两个节点:将n + 1的next指向n
反转多个节点:双指针遍历链表,重复上述操作

解题步骤
双指针一前一后遍历链表
反转双指针
在这里插入图片描述
时间复杂度O(n),空间复杂度O(1)

LeetCode:2.两数相加

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

解题思路
小学数学题,模拟相加操作
需要遍历链表

解题步骤
新建一个空链表
遍历被相加的两个链表,模拟相加操作,将个位数追加到新链表上,将十位数留到下一位去相加
在这里插入图片描述
时间复杂度O(n),空间复杂度O(n)

LeetCode:83.删除排序链表中的重复元素

输入:1 -> 1 -> 2
输出:1 -> 2

解题思路
因为链表是有序的,所以重复元素一定相邻
遍历链表,如果发现当前元素和下个元素值相同,就删除下个元素值

解题步骤
遍历链表,如果发现当前元素和下个元素值相同,就删除下个元素值
遍历结束后,返回原链表的头部
在这里插入图片描述
时间复杂度O(n),空间复杂度O(1)

LeetCode:141.环形链表

在这里插入图片描述
解题思路
两个人在圆形操场上的起点同时起跑,速度快的人一定会超过速度慢的人一圈
用一快一慢两个指针遍历链表,如果指针能够相逢,那么链表就有圈

解题步骤
用一快一慢两个指针遍历链表,如果指针能够相逢,就返回true
遍历结束后,还没有相逢就返回false
在这里插入图片描述
时间复杂度O(n),空间复杂度O(1)

前端与链表(JS中的原型链)

原型链简介
原型链的本质是链表
原型链上的节点是各种原型对象,比如Function.prototype、Object.prototype…
原型链通过__proto__属性链接各种原型对象
原型链长啥样
obj -> Object.prototype -> null
func -> Function.prototype -> Object.prototype -> null
arr -> Array.prototype -> Object.prototype -> null
原型链知识点
如果A沿着原型链能找到B的原型对象(B.prototype),那么A instanceof B为true
如果在A对象上没有找到x属性,那么会沿着原型链找x属性

const obj = {}
const func = () => {}
const arr = []
//原型链通过__proto__属性链接各种原型对象
console.log(obj .__proto__ === Object.prototype) //true
console.log(func.__proto__ === Function.prototype) //true
console.log(func.__proto__.__proto__ === Object.prototype) //true
console.log(arr.__proto__ === Array.prototype) //true
console.log(arr.__proto__.__proto__ === Object.prototype) //true

//如果A沿着原型链能找到B的原型对象(B.prototype),那么A instanceof B为true
console.log(func instanceof Function) //true
console.log(func instanceof Object) //true
//fuc的proto属性指向Function的原型对象,
//func即是object的实例,也是function的实例

//如果在A对象上没有找到x属性,那么会沿着原型链找x属性
const obj = {};
Object.prototype.x = 'x'
const func = () => {};
Function.prototype.y = 'y'
console.log(obj.x) //x
console.log(obj.y) //undefined
console.log(func.x) //x
console.log(func.y) //y

一、instanceof的使用,并用代码实现

分析
知识点:如果A沿着原型链能找到B.prototype,那么A instanceof B为true
解法:遍历A的原型链,如果找到B.prototype,返回true,否则返回false

const instanceOf = (A,B) => {
	let p = A;
	while (p) {
		if (p === B.prototype) {
			return true;
		}
		p = p.__proto__;
	}
	return false;
}
 

var foo = {},F = Function(){};
Object.prototype.a = 'value a';
Function.prototype.b = 'value b'

console.log(foo.a)
console.log(foo.b)

console.log(F.a)
console.log(F.b)
 

分析
知识点:如果在A对象上没有找到x属性,那么会沿着原型链找x属性
解法:明确foo和F变量的原型链,沿着原型链找a属性和b属性

前端链表:使用链表指针获取JSON的节点值

const json = {
	a: { b: { c: 1 } },
	d: { e: 2 },  
}
const path = ['a', 'b' ,'c']
let p =json;
path.forEach(k => {
	p = p[k];
})
 

总结

链表里的元素存储不是连续的,之间通过next连接
JavaScript中没有链表,但可以用Object模拟链表
链表常用操作:修改next、遍历链表
JS中的原型链也是一个链表
使用链表指针可以获取JSON的节点值

思考题

1、编写一个 instanceOf 方法,可以判断一个变量是否是另一个变量的实例
2、请判断一个链表是否为回文链表。题目链接:https://leetcode-cn.com/problems/palindrome-linked-list/

1.算法是程序的灵魂,优秀的程序在对海量数据处理时,依然保持高速计算,就需要高效的数据结构和算法支撑。2.网上数据结构和算法的课程不少,但存在两个问题:1)授课方式单一,大多是照着代码念一遍,数据结构和算法本身就比较难理解,对基础好的学员来说,还好一点,对基础不好的学生来说,基本上就是听天书了2)说是讲数据结构和算法,但大多是挂羊头卖狗肉,算法讲的很少。 本课程针对上述问题,有针对性的进行了升级 3)授课方式采用图解+算法游戏的方式,让课程生动有趣好理解 4)系统全面的讲解了数据结构和算法, 除常用数据结构和算法外,还包括程序员常用10大算法:二分查找算法(非递归)、分治算法、动态规划算法、KMP算法、贪心算法、普里姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法、马踏棋盘算法。可以解决面试遇到的最短路径、最小生成树、最小连通图、动态规划等问题及衍生出的面试题,让你秒杀其他面试小伙伴3.如果你不想永远都是代码工人,就需要花时间来研究下数据结构和算法。教程内容:本教程是使用Java来讲解数据结构和算法,考虑到数据结构和算法较难,授课采用图解加算法游戏的方式。内容包括: 稀疏数组、单向队列、环形队列、单向链表、双向链表、环形链表、约瑟夫问题、栈、前缀、中缀、后缀表达式、中缀表达式转换为后缀表达式、递归与回溯、迷宫问题、八皇后问题、算法的时间复杂度、冒泡排序、选择排序、插入排序、快速排序、归并排序、希尔排序、基数排序(桶排序)、堆排序、排序速度分析、二分查找、插值查找、斐波那契查找、散列、哈希表、二叉树、二叉树与数组转换、二叉排序树(BST)、AVL树、线索二叉树、赫夫曼树、赫夫曼编码、多路查找树(B树B+树和B*树)、图、图的DFS算法和BFS、程序员常用10大算法、二分查找算法(非递归)、分治算法、动态规划算法、KMP算法、贪心算法、普里姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法马踏棋盘算法。学习目标:通过学习,学员能掌握主流数据结构和算法的实现机制,开阔编程思路,提高优化程序的能力。
©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页