스크립트 데이터 구조 [시리즈] 05- LinkedList의 목록
도로 노동자 CoderMonkey 코드
, 저자 및 소스를 표시하시기 바랍니다 재현
1. 쇄 인식 구조 (단일 연결리스트)
또한 선형 사슬 구조
- 링크 된 목록 노드 구성
- 각 노드는 포인터 필드와 데이터 저장 필드를 포함
- 도메인 표현하여 노드 포인터 관계
아래 텍스처 APPEND 방법의 참조 목록 구조도
배열, 연결리스트와 비교 :
- 아니 초기 크기를 지정해야합니다
- 용량 확장을 축소 할 필요가 없습니다
- 메모리 사용
- 요소의 삽입 및 삭제의 용이성
-
- 하나의 필수 프로브로하지 첨자 직접 액세스, 하나
2. 일반적인 방법 목록
우리는 다음과 같은 일반적인 방법을 구현합니다 :
방법 | 기술 |
---|---|
APPEND (데이터) | 목록에 요소 추가 |
인서트 (위치 데이터) | 지정된 위치에 요소를 삽입하려면 |
삭제 (데이터) | 요소 제거 |
RemoveAt을 (위치) | 지정된 위치의 요소를 삭제 |
업데이트 (위치 데이터) | 지정된 위치의 요소를 업데이트 |
의 getItem (위치) | 지정된 위치의 요소를 찾기 |
같이 IndexOf (데이터) | 소자의 총수를 취득 |
크기() | 목록의 크기를 가져옵니다 |
비었다() | 목록이 비어 있는지 확인 |
명확한() | 빈 목록 |
toString () | 캐릭터 라인 |
참고 : 우리가 참조 유형의 복잡성을 고려하지 않을 것이다이 때
3. 코드 구현
참고 :
ES6 버전 코드가 구현 NPM 패키지 데이터 구조체-JS 코드를 체크 아웃은
찾을 수 있습니다 Github에서 / Gitee에
NPM 데이터 구조체-JS를 설치
통해 Objectlist 포장
/**
* 链表:单向链表
*/
function LinkedList() {
// 记录链表首个元素
this.__head = null
// 记录链表元素个数
this.__count = 0
// 用Node表示链表内部元素
function Node(data) {
this.data = data
this.next = null
Node.prototype.toString = function () {
return this.data.toString()
}
}
}
3.1 APPEND (데이터)
분석을 달성 :
- 빈리스트에 삽입하는 경우 :
새로운 노드 1.1 HEAD 포인트 삽입
1.2 다음에 널 포인트를 새 노드
- 비어 있지 않은 목록에 삽입 할 때 :
요소 목록의 끝에 다음 2.1 신규 요소를 가리
다음 널 새로운 소자에 2.2 점
LinkedList.prototype.append = function (data) {
// 1.创建新元素
var newNode = new Node(data)
// 2.1链表为空时,直接添加到末尾
if (this.__count === 0) {
this.__head = newNode
}
// 2.2链表非空时,探查到末尾元素并添加新元素
else {
var current = this.__head
while (current.next) {
current = current.next
}
current.next = newNode
}
// 3.内部计数加1
this.__count += 1
return true
}
注:
添加元素方法,记得最后给元素个数记录加1
通过上图示例,体会:HEAD 概念和元素节点的 Next 指向修改
3.2 insert(position, data)
实现分析:
- 插入方法接收两个参数:位置,数据
- 可插入位置的范围:0~length
- 插入目标位置:0 的情况
- 新元素的 next 指向原首位元素
- 将HEAD指向新元素
- 循环到指定位置
- 期间记录上一个元素及当前元素
- 在上一个元素与当前元素中间加入要插入的元素
- (修改相关指向,具体参考下面代码)
- 插入元素方法,记得最后给元素个数记录加1
LinkedList.prototype.insert = function (position, data) {
// 1.边界检查(插入位置)
if (position < 0 || position > this.__count) return false
// 2.创建新元素
var newNode = new Node(data)
// 3.1插入到链表头部
if (position === 0) {
newNode.next = this.__head
this.__head = newNode
}
// 3.2以外(包括插入到末尾)
else {
var previous = null
var current = this.__head
var index = 0
while (index < position) {
previous = current
current = current.next
index++
}
previous.next = newNode
newNode.next = current
}
// 4.内部计数加1
this.__count += 1
return true
}
注:只有在 insert 时的 position 检查规则与其它不同
3.3 remove(data)
实现分析:
- 删除元素方法接收一个参数:数据
- 根据指针循环查找
- 将从参数收到的数据与当前元素的数据进行比较
#复杂引用类型的时候通过传入自定义比较的回调函数来解决- 找到指定元素后,修改上一元素的 next 指向
注意当删除第一个元素时的特殊情况(修改HEAD指向)
删除元素完成后,记得最后给元素个数记录减1
LinkedList.prototype.remove = function (data) {
var current = this.__head
var previous = null
while (current) {
// 找到指定数据的元素,让当前元素不再被引用
if (current.data == data) {
if (previous == null) {
// 没有前元素,要删除的是首元素,修改 Head 指针
this.__head = current.next
} else {
// 修改前元素内部指针
previous.next = current.next
}
// 内部计数减1
this.__count -= 1
// 处理完成,返回 true
return true
}
previous = current
current = current.next
}
// 查找到最后没有找到指定数据的元素,返回 false
return false
// 注:
// 也可以通过调用 indexOf 获取下标后再调用 removeAt 来实现
// 只是返回值会不同,看实际需要
}
3.4 removeAt(position)
实现分析:
- 删除指定位置元素,接收一个参数:位置下标值
- 基于元素指向循环查找
- 到达指定下标元素时,将其前后元素关联,即达到删除效果
删除元素完成后,记得最后给元素个数记录减1
LinkedList.prototype.removeAt = function (position) {
// 1.边界检查
if (position < 0 || position >= this.__count) return false
var index = 0
var previous = null
var current = this.__head
// 2.找到指定位置元素
while (index++ < position) {
previous = current
current = current.next
}
// 3.使当前元素不再被引用
if (previous == null) {
// position=0 删除首元素的时候
this.__head = current.next
} else {
previous.next = current.next
}
// 4.内部计数减1
this.__count -= 1
return current.data
}
3.5 update(position, data)
实现分析:参看注释
LinkedList.prototype.update = function (position, data) {
// 1.边界检查
if (position < 0 || position >= this.__count) return false
var current = this.__head
var index = 0
// 2.找到指定位置元素
while (index++ < position) {
current = current.next
}
// 3.修改当前元素数据
current.data = data
// 4.修改完成,返回 true
return true
}
3.6 getItem(position)
获取指定位置元素的值
LinkedList.prototype.getItem = function (position) {
// 边界检查
if (position < 0 || position >= this.__count) return
var index = 0
var current = this.__head
while (index < position) {
current = current.next
index += 1
}
return current.data
}
3.7 indexOf(data)
实现分析:
- 获取元素所在位置下标值方法,接收一个参数:元素的数据
- 根据元素 next 指向循环查找
- 找到时返回当前下标
- 找不到时返回 -1
LinkedList.prototype.indexOf = function (data) {
var current = this.__head
var index = 0
while (current) {
if (current.data == data) {
return index
}
current = current.next
index += 1
}
return -1
}
3.8 size()
查看元素个数方法
LinkedList.prototype.size = function () {
return this.__count
}
3.9 isEmpty()
判空方法
LinkedList.prototype.isEmpty = function () {
return this.__count === 0
}
3.10 clear()
实现分析:
Head指向置空
计数清零
LinkedList.prototype.clear = function () {
this.__head = null
this.__count = 0
}
3.11 toString()
为了方便查看实现的字符串化方法
LinkedList.prototype.toString = function () {
var str = '[HEAD] -> '
var current = this.__head
while (current) {
str += current.data + ' -> '
current = current.next
}
if (str === '[HEAD] -> ') {
str = '[HEAD] -> Null'
}
return str
}
总结两点:
- 상기 위치 인덱스 값과 관련 동작을 통해,
이 사이클을 통해 인덱스 값을 찾을 수있다,
첨자없이리스트 구조 배열 자체는 달리.
- 수신 된 인덱스 값이 모든 방법을
실시한다의 경계를 확인하기 위해, 상기 삽입은 길이가 동일 할 수있다 때
3.12 전체 코드
/**
* 链表:单向链表
*/
function LinkedList() {
// 记录链表首个元素
this.__head = null
// 记录链表元素个数
this.__count = 0
// 用Node表示链表内部元素
function Node(data) {
this.data = data
this.next = null
Node.prototype.toString = function () {
return this.data.toString()
}
}
/**
* 添加节点
*/
LinkedList.prototype.append = function (data) {
// 1.创建新元素
var newNode = new Node(data)
// 2.1链表为空时,直接添加到末尾
if (this.__count === 0) {
this.__head = newNode
}
// 2.2链表非空时,探查到末尾元素并添加新元素
else {
var current = this.__head
while (current.next) {
current = current.next
}
current.next = newNode
}
// 3.内部计数加1
this.__count += 1
return true
}
/**
* 插入节点
*/
LinkedList.prototype.insert = function (position, data) {
// 1.边界检查(插入位置)
if (position < 0 || position > this.__count) return false
// 2.创建新元素
var newNode = new Node(data)
// 3.1插入到链表头部
if (position === 0) {
newNode.next = this.__head
this.__head = newNode
}
// 3.2以外(包括插入到末尾)
else {
var previous = null
var current = this.__head
var index = 0
while (index < position) {
previous = current
current = current.next
index++
}
previous.next = newNode
newNode.next = current
}
// 4.内部计数加1
this.__count += 1
return true
}
/**
* 删除节点
*/
LinkedList.prototype.remove = function (data) {
var current = this.__head
var previous = null
while (current) {
// 找到指定数据的元素,让当前元素不再被引用
if (current.data == data) {
if (previous == null) {
// 没有前元素,要删除的是首元素,修改 Head 指针
this.__head = current.next
} else {
// 修改前元素内部指针
previous.next = current.next
}
// 内部计数减1
this.__count -= 1
// 处理完成,返回 true
return true
}
previous = current
current = current.next
}
// 查找到最后没有找到指定数据的元素,返回 false
return false
// 注:
// 也可以通过调用 indexOf 获取下标后再调用 removeAt 来实现
// 只是返回值会不同,看实际需要
}
/**
* 删除指定位置节点
*/
LinkedList.prototype.removeAt = function (position) {
// 1.边界检查
if (position < 0 || position >= this.__count) return false
var index = 0
var previous = null
var current = this.__head
// 2.找到指定位置元素
while (index++ < position) {
previous = current
current = current.next
}
// 3.使当前元素不再被引用
previous.next = current.next
// 4.内部计数减1
this.__count -= 1
return current.data
}
/**
* 更新节点
*/
LinkedList.prototype.update = function (position, data) {
// 1.边界检查
if (position < 0 || position >= this.__count) return false
var current = this.__head
var index = 0
// 2.找到指定位置元素
while (index++ < position) {
current = current.next
}
// 3.修改当前元素数据
current.data = data
// 4.修改完成,返回 true
return true
}
/**
* 获取指定位置节点
*/
LinkedList.prototype.getItem = function (position) {
// 边界检查
if (position < 0 || position >= this.__count) return
var index = 0
var current = this.__head
while (index < position) {
current = current.next
index += 1
}
return current.data
}
/**
* 获取节点位置下标
*/
LinkedList.prototype.indexOf = function (data) {
var current = this.__head
var index = 0
while (current) {
if (current.data == data) {
return index
}
current = current.next
index += 1
}
return -1
}
/**
* 获取链表长度
*/
LinkedList.prototype.size = function () {
return this.__count
}
/**
* 是否为空链表
*/
LinkedList.prototype.isEmpty = function () {
return this.__count === 0
}
/**
* 清空链表
*/
LinkedList.prototype.clear = function () {
this.__head = null
this.__count = 0
}
LinkedList.prototype.toString = function () {
var str = '[HEAD] -> '
var current = this.__head
while (current) {
str += current.toString() + ' -> '
current = current.next
}
if (str === '[HEAD] -> ') {
str = '[HEAD] -> Null'
}
return str
}
}
4. 테스트
// ---------------------------------------------
// Test: LinkedList
// ---------------------------------------------
console.log('----Test: LinkedList----')
var lst = new LinkedList()
lst.append('a')
lst.append('b')
lst.append('c')
console.log(lst.toString())
lst.insert(1, 'insert-1')
console.log(lst.toString())
lst.insert(4, 'insert-4')
console.log(lst.toString())
lst.insert(0, 'insert-0')
console.log(lst.toString())
lst.remove('c')
console.log(lst.toString(), 'remove-c')
console.log('indexOf-b : ', lst.indexOf('b'))
lst.update(3, 'b-updated')
console.log('update-b : ', lst.toString())
lst.removeAt(3)
console.log('after removeAt(3) : ', lst.toString())
lst.clear()
console.log('after clear : ', lst.toString())
출력보기 :
----Test: LinkedList----
[HEAD] -> a -> b -> c ->
[HEAD] -> a -> insert-1 -> b -> c ->
[HEAD] -> a -> insert-1 -> b -> c -> insert-4 ->
[HEAD] -> insert-0 -> a -> insert-1 -> b -> c -> insert-4 ->
[HEAD] -> insert-0 -> a -> insert-1 -> b -> insert-4 -> remove-c
indexOf-b : 3
update-b : [HEAD] -> insert-0 -> a -> insert-1 -> b-updated -> insert-4 ->
after removeAt(3) : [HEAD] -> insert-0 -> a -> insert-1 -> insert-4 ->
after clear : [HEAD] -> Null
결과는 정확합니다.
하루에 전화.
NPM은 툴킷을 data-struct-js
,
, ES6 구현 자바 스크립트 데이터 구조를 기반으로
작은 바퀴가 거의 사용되지 않지만,
아마도 약간의 도움이 될 것입니다 자바 스크립트를 배울 수있는 초보자를위한.
단순히 당신이 관심 캔도에 갈 수있는 설치
GitHub의 / Gitee의 소스 코드를 볼. (스타 테이블 지원 ~)
npm install data-struct-js --save-dev
https://github.com/CoderMonkie/data-struct-js
https://gitee.com/coder-monkey/data-struct-js
마지막으로, ~ 읽기와 성원에 감사드립니다