顺序存储、链式存储。
2020-6-27 更新
- 单链表的数据结构体:
function Node(){ this.val = null; this.next = null; }
- 新增单链表的实现;
线性表可以在任意位置插入和删除一个数据。
概念定义
除第一个和最后一个元素外,每个数据只有一个前驱数据元素和一个后继数据元素。
操作:
- 初始化List(len);
- 返回当前线性表元素个数.
- 插入数据元素Insert(i,val):在线性表
List
中的第i
位置插入数据val
. - 删除数据元素Delete(i):删除线性表
List
中的第i
元素。 - 取数据元素Get(i,x):取线性表
List
的第i
各元素。
顺序表
说明:
- 指定最大存储
len
; - 记录当前数据元素个数
size
; - 数据插入时按序插入,即
0<=i<=size
;时间复杂度为O(n) - 数据删除时不能
i<0 || i>size-1
;时间复杂度为O(n) - 取值时不能去无效的下标值,即
0<=i<size
代码实现:
function queueList(len){
// 最大空间
this.MaxSize = len;
// 存储的数据类型使用数组
this.list = new Array(len);
// 当前数据元素个数
this.size = 0;
}
queueList.prototype = {
getLen(){
return this.size;
},
insert(i,val){
// 数据插入
if(this.size>=this.MaxSize){
console.error("顺序表已满,无法插入!");
return false;
}else if(i<0 || i>this.size){
console.error("参数i不合法!");
return false;
}else{
// 执行顺序插入,将>i 后面的元素移位。
for(let j=this.size;j>i;j--){
this.list[j] = this.list[j-1];
}
this.list[i] = val;
this.size++;
return true;
}
},
delete(i){
// 删除元素
if(this.size<=0){
console.error("顺序表无数据可删!");
return false;
}else if(i<0 || i>this.size-1){
console.error("参数i不合法!");
return false;
}else{
for(let j=i+1;j<this.size - 1;j++){
this.list[j -1] = this.list[j];
}
this.size--;
return true;
}
},
getVal(i){
// 获取指定位置的元素数据
if(i<0 || i>this.size-1){
console.error("参数i不合法!");
return false;
}
return this.list[i];
}
}
链式存储
把存储有数据元素的节点用指针域构造成链。
单链表存储
构成链表的节点只有一个指向直接后继节点的指针域。
说明:
- 定义默认的头结点
head
为键值0
,头结点不存储数据;指向的下一节点为数据0
; - 各个节点的数据对象
{ val:null, // 节点值 next:null, // 下一节点指向 }
- 使用
Symbol
做数据键,保证了键值的唯一性。 - 数据插入和删除都需要遍历查找去处理,所以时间复杂度为O(n);
2020-6-27 更新后 实现:
// 节点的数据结构体:
function Node(){
this.val = null;
this.next = null;
}
/**
* Initialize your data structure here.
*/
var MyLinkedList = function() {
this.head = null;
};
/**
* 初始化头部
*/
MyLinkedList.prototype.init = function(){
// 初始化 头部接节点
this.head = new Node();
this.head.next = null;
}
/**
* 获取链表的长度
*/
MyLinkedList.prototype.getLen = function(){
//
let p = this.head;
let size = 0;
while(p.next!==null){
p = p.next;
size++;
}
return size;
}
/**
* Get the value.
* @param {number} index
* @return {number}
*/
MyLinkedList.prototype.get = function(index) {
let p = this.head;
let j = -1;
// 查找值
while(p.next!==null && j<index){
p = p.next;
j++;
}
if(j!=index){
console.error("取元素参数错误!");
return -1;
}
return p.val;
};
/**
* Add a node
* @param {number} index
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtIndex = function(index, val) {
let p = this.head;
// 查找index处的节点元素
let j = -1;
while(p.next!==null && j<index-1){
p =p.next;
j++;
}
if(j!==index-1){
console.error("插入元素位置错误!");
return -1;
}
let temp = new Node();
temp.val = val;
temp.next = p.next;
p.next = temp;
return true;
};
/**
* Delete
* @param {number} index
* @return {void}
*/
MyLinkedList.prototype.deleteAtIndex = function(index) {
let p = this.head;
let j = -1;
while(p.next!==null &&p.next.next!=null && j<index-1){
p = p.next;
j++;
}
if(j!==index-1){
console.error("删除元素位置错误!");
return false;
}
p.next = p.next.next;
return true;
};
不采用了
var MyLinkedList = function() {
// 其数据结构应该是一个对象,键值对保存
// 且默认键值‘0’ 为head
this.list = {
'0':{
next:null
}
};
// 数据元素
this.attr = {
val:null,
next:null
}
};
MyLinkedList.prototype.get = function(index) {
let head = this.list["0"];
let j = -1;
// 查找值
while(head && head.next!==null && j<index){
head = this.list[head.next];
j++;
}
if(j!=index){
console.error("取元素参数错误!");
return -1;
}
return head.val;
};
MyLinkedList.prototype.addAtHead = function(val) {
let obj = Object.assign({},this.attr);
// 头
let head = this.list["0"];
obj.val = val;
let time = Symbol();
if(head.next!=null){
obj.next = head.next
}
head.next = time;
this.list[time] = obj;
return true;
};
MyLinkedList.prototype.addAtTail = function(val) {
let obj = Object.assign({},this.attr);
//
obj.val = val;
let tail = this.list["0"];
while(tail.next!==null){
tail = this.list[tail.next];
}
let time = Symbol();
tail.next = time;
this.list[time] = obj;
return true;
};
MyLinkedList.prototype.addAtIndex = function(index, val) {
let obj = Object.assign({},this.attr);
// 头/默认 指向第一个元素
let head = this.list["0"];
// 查找index处的节点元素
let j = -1;
while(head.next!==null && j<index-1){
head = this.list[head.next];
j++;
}
if(j!==index-1){
console.error("插入元素位置错误!");
return -1;
}
obj.val = val;
let time = Symbol();
obj.next = head.next;
head.next = time;
this.list[time] = obj;
return true;
};
MyLinkedList.prototype.deleteAtIndex = function(index) {
let head = this.list["0"];
let j = -1;
while(head.next!==null &&this.list[head.next].next!=null && j<index-1){
head = this.list[head.next];
j++;
}
if(j!==index-1){
console.error("删除元素位置错误!");
return false;
}
// 更改指向
let id = head.next;
head.next = this.list[head.next].next;
// 删除数据
Reflect.deleteProperty(this.list,id);
return true;
};
循环单链表
单链表中最后一个节点的next
指向头结点head
,单链表示例的0
键值。
区别描述:
- 初始化时,头结点指向
'0':{ next:'0' }
- 在其他函数比较中。
head.next!=null
改为head.next!='0'
;
双向链表
区别与单链表:每个节点有一个前驱指针,指向上一个节点。也分循环和非循环双向链表。
说明:
- 链表头部节点更改为
'0'{ prior:'0', next:'0' } // 数据节点格式 { prior:null, val:null, next:null }
- 其中的数据操作区别于多次交换前驱节点、后驱节点的前指针和后指针的指向。