初学数据结构,链表给我的感觉相较于数组栈队列,是更加烧脑的,没搞懂时容易把人搞晕,现在总结下它的基础原理和方法。
简单链表结构
其中链表头像是火车头指向下一个车厢,如果没有车厢则指向null,车厢数据存放数据元素,指针是链接下一节车厢的钩子,通过指针钩子找到下一节车厢,如果没有下一届车厢也指向null。
实现一下简单链表的常见方法
function abc() {
//创建链表对象
function obj (data) {
this.key = data,
this.value = null
}
this.length = 0
this.objs = ''
//向末尾插入
abc.prototype.append = function (data) {
var obj2 = new obj(data)
if(this.objs.length == 0) {
this.objs = obj2
} else {
var parameter = this.objs
while(parameter.value) {
parameter = parameter.value
}
parameter.value = obj2
}
this.length += 1
}
//将链表所有元素打印
abc.prototype.tostring = function () {
var parameter = this.objs
var chr = ''
for (var i=0; i
chr += parameter.key
parameter = parameter.value
}
return chr
}
//向指定位置插入
abc.prototype.insert = function (num, data) {
if(num<0 || num>this.length) return false
var parameter = this.objs
var obj2 = new obj(data)
var index = 0
while(index++ < num-1) {
parameter = parameter.value
}
var parameter2 = parameter.value
parameter.value = obj2
parameter.value.value = parameter2
this.length += 1
}
//将某个位置值更新
abc.prototype.updata = function (num, data) {
if(num>this.length-1) return false
var parameter = this.objs
var parameter = this.objs
for(var i=0; i
parameter = parameter.value
}
parameter.key = data
}
//将特定下标值删除
abc.prototype.removeAt = function (num) {
if(num>this.length-1) return false
if(num==0) {
this.objs = null
this.length = 0
return
}
var parameter = this.objs
for(var i=0; i
parameter = parameter.value
}
parameter.value = null
this.length = this.length - num
}
//将特定属性值删除
abc.prototype.remove = function (obj) {
var parameter = this.objs
for(var i=0; i
if(parameter.key == obj) {
parameter = null
this.length = i
return this.objs
}
parameter = parameter.value
}
return false
}
//返回是否为空
abc.prototype.isEmpty = function () {
return this.objs.length == 0
}
//返回长度
abc.prototype.size = function () {
return this.length
}
//返回指定下标值
abc.prototype.get = function (num) {
if(num > this.length-1) return false
var parameter = this.objs
for(var i=0; i<=num-1; i++) {
parameter = parameter.value
}
console.log(this.objs);
return parameter
}
//判断是否有此值
abc.prototype.indexof = function (data) {
var parameter = this.objs
for(var i=0; i
if(parameter.key == data) {
return i
}
parameter = parameter.value
}
return -1
}
}
var abc2 = new abc()
abc2.append('qwer')
abc2.append('asdf')
abc2.append('zxcv')
abc2.insert(3, 'poiu')
abc2.updata(2, 'qqqq')
// abc2.removeAt(2)
// console.log(abc2.remove('asdf'))
console.log(abc2.indexof('asdf')); //1
console.log(abc2.get(2)) //{key: "qqqq", value: obj}
console.log(abc2.tostring()) //qwerasdfqqqqpoiu
console.log(abc2.isEmpty()); //false
console.log(abc2.objs); //{key: "qwer", value: obj}
总结下方法就是,增删查改,对于容器类的数据结构来说,最重要的事就是增删查改,如何高效优雅的对数据结构进行增删查改就是一个好的算法应该干的事。
除了单向链表,还有双向链表,而双向链表的出现是为了解决单向链表,逆序查找值非常不方便而出现的。
双向链表结构
废话少说,直接进入封装双向链表常见方法阶段。
function abc () {
function node (praevia, data) {
this.praevia = praevia
this.data = data
this.postf = null
}
this.length = 0
//第一个元素
this.objs = {}
//最后一个元素
this.tail = {}
//从链表最后插入一个节点
abc.prototype.append = function (data) {
if(this.length == 0) {
var obj2 = new node(null, data)
this.objs = obj2
} else {
var parameter = this.objs
while(parameter.postf) {
parameter = parameter.postf
}
var obj2 = new node(parameter, data)
parameter.postf = obj2
}
this.length += 1
this.tail = obj2
return this.objs
}
//将链表以字符串形式打印出来
abc.prototype.tostring = function () {
var num = 0
var chr = ''
var parameter = this.objs
while(num++ < this.length) {
chr += parameter.data + ' '
parameter = parameter.postf
}
return chr
}
//将链表以正序形式打印出来
abc.prototype.forwardstring = function () {
return this.tostring()
}
//将链表以倒叙形式打印出来
abc.prototype.backwordstring = function () {
var num = 0
var arr = []
var chr = ''
var parameter = this.objs
while(num++ < this.length) {
arr.push(parameter.data)
parameter = parameter.postf
}
while(num-- > 1) {
chr += arr.pop() + ' '
}
return chr
}
//向列表特定下标插入值
abc.prototype.insert = function (num, data) {
if(num > this.length || num < 0) return false
var index = 0
var parameter = this.objs
if(num == 0) {
var obj2 = new node(null, data)
obj2.postf = this.objs
this.objs.praevia = obj2
this.objs = obj2
this.length += 1
return
}
while(index++ < num-1) {
parameter = parameter.postf
}
var obj2 = new node(parameter, data)
obj2.postf = parameter.postf
parameter.postf = obj2
if(num==this.length) {
this.tail = obj2
}
this.length += 1
}
//获得特定下标处元素
abc.prototype.get = function (num) {
var index = 0
var parameter = this.objs
while(index++ < num) {
parameter = parameter.postf
}
return parameter
}
//修改特定下标的值
abc.prototype.updata = function (num, data) {
var obj2 = this.get(num)
obj2.data = data
}
//删除方法
abc.prototype.delete = function (parameter) {
var head = parameter.praevia
var foot = parameter.postf
parameter.praevia.postf = foot
parameter.postf.praevia = head
this.length -= 1
}
//删除特定下标处的值
abc.prototype.removeAt = function (num) {
if(num<0 || num>this.length-1) return null
var index = 0
var parameter = this.objs
if(num==0) {
parameter = parameter.postf
parameter.praevia = null
this.objs= parameter
this.length -= 1
return this.objs
}
while(index++ < num) {
parameter = parameter.postf
}
if(num==this.length-1) {
var a = parameter.praevia
this.tail = a
}
this.delete(parameter)
}
//删除特定的元素
abc.prototype.remove = function (data) {
var index = 0
var parameter = this.objs
while(index++ < this.length) {
if(parameter.data == data) {
if(index==this.length-1) {
var a = parameter.praevia
this.tail = a
}
this.delete(parameter)
return this.objs
}
parameter = parameter.postf
}
return -1
}
}
var newNode = new abc()
newNode.append('abcd')
newNode.append('asdf')
newNode.append('zxcv')
newNode.insert(2, 'mnbv')
newNode.insert(0, 'dfgh')
newNode.updata(2 , 'liuy')
newNode.removeAt(3)
console.log(newNode.remove('asdfas')) //-1
console.log(newNode.remove('abcd')) //Object
console.log(newNode.tostring()); //dfgh liuy zxcv
console.log(newNode.forwardstring()); //dfgh liuy zxcv
console.log(newNode.backwordstring()); //zxcv liuy dfgh
console.log(newNode.get(3)); //null
console.log(newNode.tail); //Object
和单向链表相比,因为多了一层关系,所以在删除添加时需要多一层操作把上个指针拿到并赋值,搞懂了单层链表就不是很难。