java算法判断链表有没有闭环,前端算法系列之二:数据结构链表、双向链表、闭环链表、有序链表...

news/2024/7/7 12:48:22

前言

上一次我们讲到了数据结构:栈和队列,并对他们的运用做了一些介绍和案例实践;我们也讲到了怎么简单的实现一个四则运算、怎么去判断标签是否闭合完全等等,anyway,今天接着和大家介绍一些数据结构:

上一篇:前端算法系列之一:时间复杂度、空间复杂度以及数据结构栈、队列的实现

链表

链表是一种怎么样的结构呢?链表就是一种可以把数据串联起来的结构,每个元素会有指向下一个元素的指针(末尾的没有普通链表),就像现实世界中的火车一样一节一节的串联起来;链表根据自身的指针指向又可以分为:单向链表、双向链表、循环链表;

1460000039094981

1460000039094978

链表首先会有一个表头,表头作为起始的指针,然后每一个元素我们称作为节点(node);每个节点有一个指向下一个节点的指针(next),直到链表的末尾指针会指向undefined;

链表的实现

1、节点

节点的创建和定义;每个节点会有一个保存自己数据的属性(element),然后有一个指针(next)export class Node {

constructor(element, next = null) {

this.element = element;

this.next = next;

}

}

2、链表的api

getElementAt(position): 获取某个位置的元素

append(element): 向链表末尾中添加元素

removeAt(idx): 移除某个元素

insert(element, position = 0, dir = 'before'): 向指定位置添加元素

insertAfter(element, position): 向指定的位置后面添加元素

size(): 链表的长度

remove(): 删除链表末端元素

removeAll(): 删除整个链表

isEmpty(): 检查链表是否为空import { defaultEquals } from "../util.js";

import { Node } from './Node.js'

export default class LinkedList {

constructor(equalsFn = defaultEquals) {

this.count = 0;

this.head = null;

this.equalsFn = equalsFn;

}

getElementAt(position) {

if(position >= 0 && position <= this.count) {

let node = this.head;

for (let i = 0; i < position && !!node; i++) {

node = node.next;

}

return node;

}

return undefined;

}

insertAfter(element, position) {

return this.insert(element, position, 'after');

}

size() {

return this.count;

}

remove() {

return this.removeAt(this.size() - 1);

}

removeAll() {

this.count = 0;

this.head = null;

}

isEmpty() {

return this.size() === 0;

}

getHead() {

return this.head;

}

}

3、链表末尾添加一个元素append;append(element) {

const node = new Node(element);

let current = this.head;

if(current == null) {

this.head = node;

} else {

current = this.head;

while (current.next != null) {

current = current.next;

}

current.next = node

}

this.count++;

return element;

}

1460000039094977

4、插入一个元素insert(element, position = 0, dir = 'before') {

if (element === undefined) {

throw Error('缺少需要插入的元素');

return;

}

if (position >= this.count) {

return this.append(element);

}

const node = new Node(element);

const targetNode = dir === 'before' ? this.getElementAt(position - 1) : this.getElementAt(position);

if (!targetNode) {

let prev = this.head;

this.head = node;

node.next = prev;

} else {

let next;

next = targetNode.next

targetNode.next = node;

node.next = next;

}

this.count++;

return element;

}

1460000039094984

5、删除一个元素removeAt(idx) {

if (idx >= 0 && idx < this.count) {

let current = this.head;

if (idx === 0) {

this.head = current.next;

current.next = null;

} else {

let prev = this.getElementAt(idx - 1);

current = prev.next;

prev.next = current.next;

}

this.count--;

return current.element;

}

return undefined;

}

1460000039094982

6、双向链表

单向链表元素指向都是一个方向的,也只能被单向递归搜索,而双向链表不仅仅有指向下一个元素的指针同时具有指向上一个元素的指针;

1460000039094979import LinkedList from "./LinkedList";

import {defaultEquals} from "../util";

import { DoubleNode } from "./DoubleNode";

export default class DoubleLinkedList extends LinkedList{

constructor(equalIsFn = defaultEquals){

super(equalIsFn);

this.tail = null;// 队列尾部

}

getElementAt(position) {

if(position >= 0 && position <= this.count) {

if (position > this.count/2) {

let cur = this.tail;

for (let i = this.count - 1; i > position; i--){

cur = cur.prev;

}

return cur;

} else {

return super.getElementAt(position)

}

}

return undefined;

}

removeAll() {

super.removeAll();

this.tail = null;

}

removeAt(position) {

if (position >= 0 && position < this.count) {

let cur = this.getElementAt(position);

if(position === 0) {

this.head = cur.next;

cur.next = null;

this.prev = null;

} else if (position === this.count - 1) {

this.tail = cur.prev;

this.tail.next = null;

cur.prev = null;

} else {

let prev = cur.prev;

let next = cur.next;

prev.next = next;

next.prev = prev;

cur.prev = null;

cur.next = null;

}

this.count--;

return cur.element;

}

return undefined;

}

}

队列末尾插入元素(append)

双向链表插入元素和单向比较类似,不同的是双向不仅要链接他的下级还得关联他的前一级;append(element) {

const node = new DoubleNode(element);

if (!this.tail) {

this.head = node;

this.tail = node;

} else {

let cur = this.tail;

cur.next = node;

node.prev = cur;

this.tail = node;

}

this.count++;

return element;

}

1460000039094980

中间某个位置插入元素insert(element, position = 0, dir = 'before'){

if (element === undefined) {

throw Error('缺少需要插入的元素');

return;

}

if (position >= this.count) {

return this.append(element);

}

const node = new DoubleNode(element);

let cur;

const targetNode = dir === 'before' ? this.getElementAt(position - 1) : this.getElementAt(position);

if (!targetNode) {

cur = this.head;

node.next = cur;

cur.prev = node;

this.head = node;

} else {

let next;

next = targetNode.next

targetNode.next = node;

node.prev = targetNode;

node.next = next;

next.prev = node;

}

this.count++;

return element;

}

1460000039094983

移除某个元素也是上述相同,修改节点的前后指针就可以了,这里不再赘述,详情看源码

闭环链表

闭环链表也称环,是一个闭合的结构,尾部会指向头部

f61285cecfbe7419ee3702141517a6eb.png

有序链表

有序链表就是在append元素的时候进行排序加入从而得到一个有顺序的链表,比较函数可以根据实例化的时候传入比较函数equalIsFn;

获取第一手信息请关注我的专栏或者关注公众号

bVcQEdk


http://www.niftyadmin.cn/n/712160.html

相关文章

web前端学习(三十六)——JavaScript重要语句(if...else if...else、switch、for、while、break、continue)的相关设置

1.JS条件语句 条件语句用于基于不同的条件来执行不同的动作。 通常在写代码时&#xff0c;您总是需要为不同的决定来执行不同的动作。您可以在代码中使用条件语句来完成该任务。 在 JavaScript 中&#xff0c;我们可使用以下条件语句&#xff1a; if 语句 - 只有当指定条件为 t…

Button的四种点击事件

1.XML文件布局<Buttonandroid:id"id/bt1"android:layout_width"wrap_content"android:layout_height"wrap_content"android:onClick"doClick"android:text"XML添加doClick"android:layout_above"id/bt2"androi…

zabbix 安装 部署 网络监控

zabbix 部署详解zabbix简介是一个高度集成的网络监控解决方案&#xff0c;可以提供企业级的开源分布式监控解决方案&#xff0c;由一个国外的团队持续维护更新&#xff0c;软件可以自由下载使用&#xff0c;运作团队靠提供收费的技术支持赢利Zabbix主要功能&#xff1a;- CPU负…

python fail to execute,用python可视化文件时报ExecutableNotFound: failed to execute ['dot', '-Tsvg']的错...

如上图所示&#xff0c;运行代码之后报ExecutableNotFound: failed to execute [dot, -Tsvg], make sure the Graphviz executables are on your systems PATH的错误&#xff0c;起初以为原因是未安装graphviz模块&#xff0c;pip一下发现还是不行&#xff0c;后来才发现需要先…

一步一步学习Redis——HyperLogLog的相关命令

文章目录&#xff1a; 1.开篇 2.Redis HyperLogLog的相关命令 2.1 PFADD命令 语法 返回值 2.2 PFCOUNT命令 语法 返回值 2.3 PFMERGE命令 语法 返回值 1.开篇 Redis 在 2.8.9 版本添加了 HyperLogLog 结构。 Redis HyperLogLog 是用来做基数统计的算法&#xff0c;H…

labels用python 怎么用_Python wx.TR_EDIT_LABELS属性代码示例

# 需要导入模块: import wx [as 别名]# 或者: from wx import TR_EDIT_LABELS [as 别名]def __init__(self, parent, folder, filterNone, editableTrue):wx.Panel.__init__(self, parent, stylewx.TAB_TRAVERSAL)main_sizer wx.BoxSizer(wx.VERTICAL)self.Tree wx.TreeCtrl(…

重载new和delete运算符

内存管理运算符 new、new[]、delete 和 delete[] 也可以进行重载&#xff0c;其重载形式既可以是类的成员函数&#xff0c;也可以是全局函数。一般情况下&#xff0c;内建的内存管理运算符就够用了&#xff0c;只有在需要自己管理内存时才会重载。以成员函数的形式重载 new 运算…

工作vs.学�

近一两年来&#xff0c;我先后对&#xff3b;工作与学习&#xff3d;的复杂过程有过多次的头脑风暴&#xff0c;而且感觉在这方面略有所成&#xff08;看这里和这里&#xff09;&#xff1b;当然既然仅仅是头脑风暴&#xff0c;所谓的所成也仅仅是一些粗糙的想法&#xff0c;一…