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

前言

上一次我们讲到了数据结构:栈和队列,并对他们的运用做了一些介绍和案例实践;我们也讲到了怎么简单的实现一个四则运算、怎么去判断标签是否闭合完全等等,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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值