单链表链表结构的实现
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
class LinkedList {
constructor() {
this.length = 0;
this.head = null;
}
equalsFn(a, b) {
return a === b;
}
}
功能
- push(element):向链表尾部添加一个新元素。
- insert(element, position):向链表的特定位置插入一个新元素。
- getElementAt(index):返回链表中特定位置的元素。如果链表中不存在这样的元素,则返回undefined。
- remove(element):从链表中移除一个元素。
- indexOf(element):返回元素在链表中的索引。如果链表中没有该元素则返回-1。
- removeAt(position):从链表的特定位置移除一个元素。
- isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0 则返回false。
- size():返回链表包含的元素个数,与数组的length 属性类似。
- toString():返回表示整个链表的字符串。由于列表项使用了Node 类,就需要重写继承自JavaScript 对象默认的toString 方法,让其只输出元素的值。
push
push(val) {
let newNode = new Node(val);
let curr;
if (!this.head) {
this.head = newNode;
} else {
curr = this.head;
while (curr.next) {
curr = curr.next;
}
curr.next = newNode;
}
this.length++;
}
removeAt
removeAt(index) {
if (index < this.length && index >= 0) {
let curr = this.head;
if (index === 0) {
this.head = curr.next;
} else {
for (let i = 1; i < index; i++) {
curr = curr.next;
}
let beRemove = curr.next;
curr.next = beRemove.next;
this.length--;
return beRemove;
}
}
}
getElementAt
getElementAt(index) {
if (index < this.length && index >= 0) {
let curr = this.head;
if (index === 0) return curr;
else {
for (let i = 1; i <= index; i++) {
curr = curr.next;
}
return curr;
}
}
}
重写removeAt
removeAt(index) {
let curr = this.getElementAt(index - 1);
curr.next = curr.next.next;
insert
insert(index, value) {
let newNode = new Node(value);
if (index < this.length && index >= 0) {
let curr = this.head;
if (index === 0) {
this.head = newNode;
this.head.next = curr;
} else {
for (let i = 1; i < index; i++) {
curr = curr.next;
}
let nextNode = curr.next;
curr.next = newNode;
newNode.next = nextNode;
}
this.length++;
}
}
indexOf
indexOf(value) {
let curr = this.head;
if (this.equalsFn(curr.value, value)) {
return 0;
}
for (let i = 1; i < this.length; i++) {
curr = curr.next;
if (this.equalsFn(curr.value, value)) {
return i;
}
}
return -1;
}
removeValue
removeValue(value) {
let curr = this.head;
let prev = null;
if (this.equalsFn(curr.value, value)) {
this.head = curr.next;
this.length--;
}
for (let i = 1; i < this.length; i++) {
prev = curr;
curr = curr.next;
if (this.equalsFn(curr.value, value)) {
prev.next = curr.next;
this.length--;
}
}
return undefined;
}
toString
toString() {
let objString = "";
let curr = this.head;
if (!curr) {
return objString;
} else {
objString = `${curr.value}`;
for (let i = 1; i < this.length; i++) {
curr = curr.next;
objString = `${objString}, ${curr.value}`;
}
return objString;
}
}
完整代码
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
class LinkedList {
constructor() {
this.length = 0;
this.head = null;
}
equalsFn(a, b) {
return a === b;
}
push(val) {
let newNode = new Node(val);
let curr;
if (!this.head) {
this.head = newNode;
} else {
curr = this.head;
while (curr.next) {
curr = curr.next;
}
curr.next = newNode;
}
this.length++;
}
removeAt(index) {
let curr = this.getElementAt(index - 1);
curr.next = curr.next.next;
}
getElementAt(index) {
if (index < this.length && index >= 0) {
let curr = this.head;
if (index === 0) return curr;
else {
for (let i = 1; i <= index; i++) {
curr = curr.next;
}
return curr;
}
}
}
insert(index, value) {
let newNode = new Node(value);
if (index < this.length && index >= 0) {
let curr = this.head;
if (index === 0) {
this.head = newNode;
this.head.next = curr;
} else {
for (let i = 1; i < index; i++) {
curr = curr.next;
}
let nextNode = curr.next;
curr.next = newNode;
newNode.next = nextNode;
}
this.length++;
} else {
throw "索引值错误";
}
}
indexOf(value) {
let curr = this.head;
if (this.equalsFn(curr.value, value)) {
return 0;
}
for (let i = 1; i < this.length; i++) {
curr = curr.next;
if (this.equalsFn(curr.value, value)) {
return i;
}
}
return -1;
}
removeValue(value) {
let curr = this.head;
let prev = null;
if (this.equalsFn(curr.value, value)) {
this.head = curr.next;
this.length--;
}
for (let i = 1; i < this.length; i++) {
prev = curr;
curr = curr.next;
if (this.equalsFn(curr.value, value)) {
prev.next = curr.next;
this.length--;
}
}
return undefined;
}
toString() {
let objString = "";
let curr = this.head;
if (!curr) {
return objString;
} else {
objString = `${curr.value}`;
for (let i = 1; i < this.length; i++) {
curr = curr.next;
objString = `${objString}, ${curr.value}`;
}
return objString;
}
}
getHead() {
return this.head;
}
isEmpty() {
return this.length === 0 ? true : false;
}
size() {
return this.length;
}
}
let linkedList = new LinkedList();
linkedList.push("a");
linkedList.push("b");
linkedList.push("c");
linkedList.insert(1, "aa");
console.log(linkedList.getElementAt(2));
console.log(linkedList.indexOf("a"));
console.log(linkedList.removeValue("c"));
console.log(linkedList.size());
console.log(linkedList.isEmpty());
console.log(linkedList);
console.log(linkedList.toString());
双向链表的实现
class Node {
constructor(value) {
this.value = value;
this.next = null;
this.prev = null;
}
}
class DBLinkedList {
constructor() {
this.length = 0;
this.head = null;
}
equalsFn(a, b) {
return a === b;
}
}
双向链表需要讨论的情况
- 当结点为头结点时
- 当结点为最后一个结点时
- 当结点有且只有一个结点时
重构链表方法
class Node {
constructor(value) {
this.value = value;
this.next = null;
this.prev = null;
}
}
class DBLinkedList {
constructor() {
this.length = 0;
this.head = null;
}
equalsFn(a, b) {
return a === b;
}
push(val) {
let newNode = new Node(val);
let prev = this.head;
let curr;
if (!this.head) {
this.head = newNode;
} else {
curr = this.head;
while (curr.next) {
curr = curr.next;
prev = curr;
}
curr.next = newNode;
newNode.prev = prev;
}
this.length++;
}
removeAt(index) {
if (index < this.length && index >= 0) {
let curr = this.head;
if (index === 0) {
this.head = curr.next;
if (this.length !== 1) {
this.head.prev = null;
}
this.length--;
} else {
for (let i = 1; i < index; i++) {
curr = curr.next;
}
let beRemove = curr.next;
curr.next = beRemove.next;
if (index !== this.length - 1) {
beRemove.next.prev = curr;
}
this.length--;
return beRemove;
}
}
}
getElementAt(index) {
if (index < this.length && index >= 0) {
let curr = this.head;
if (index === 0) return curr;
else {
for (let i = 1; i <= index; i++) {
curr = curr.next;
}
return curr;
}
}
}
insert(index, value) {
let newNode = new Node(value);
if (index < this.length && index >= 0) {
let curr = this.head;
if (index === 0) {
this.head = newNode;
this.head.next = curr;
if (this.length > 1) {
this.head.prev = null;
}
} else {
for (let i = 1; i < index; i++) {
curr = curr.next;
}
let nextNode = curr.next;
curr.next = newNode;
newNode.prev = curr;
newNode.next = nextNode;
if (index !== this.length - 1) {
nextNode.prev = newNode;
}
}
this.length++;
} else {
throw "索引值错误";
}
}
indexOf(value) {
let curr = this.head;
if (this.equalsFn(curr.value, value)) {
return 0;
}
for (let i = 1; i < this.length; i++) {
curr = curr.next;
if (this.equalsFn(curr.value, value)) {
return i;
}
}
return -1;
}
removeValue(value) {
let curr = this.head;
let prev = null;
if (this.equalsFn(curr.value, value)) {
this.head = curr.next;
if (this.head) {
this.head.prev = null;
}
this.length--;
}
for (let i = 1; i < this.length; i++) {
prev = curr;
curr = curr.next;
if (this.equalsFn(curr.value, value)) {
prev.next = curr.next;
if (curr.next) {
curr.next.prev = prev;
}
this.length--;
}
}
return undefined;
}
toString() {
let objString = "";
let curr = this.head;
if (!curr) {
return objString;
} else {
objString = `${curr.value}`;
for (let i = 1; i < this.length; i++) {
curr = curr.next;
objString = `${objString}, ${curr.value}`;
}
return objString;
}
}
getHead() {
return this.head;
}
isEmpty() {
return this.length === 0 ? true : false;
}
size() {
return this.length;
}
}
循环链表的概念
- 循环链表可以像链表一样只有单向引用,也可以像双向链表一样有双向引用。
- 循环链表和链表之间唯一的区别在于,最后一个元素指向下一个元素的指针不是引用undefined,而是指向第一个元素(head)