您的位置:首页 > 理论基础 > 数据结构算法

javascript实现数据结构与算法系列:功能完整的线性链表

2014-04-16 11:19 555 查看
由于链表在空间的合理利用上和插入,删除时不需要移动等的有点,因此在很多场合下,它是线性表的首选存储结构。然而,它也存在着实现某些基本操作,如求线性表长度时不如顺序存储结构的缺点;另一方面,由于在链表中,结点之间的关系使用指针来表示,则数据元素在线性表中的“位序”的概念已淡化,而被数据元素在线性链表中的“位置”所代替。为此,从实际出发重新定义线性链表及其基本操作

结构图:



(function(module){
function List() {
this.head = null;
this.tail = null;
}
module.exports = List;

List.mergeList = function (a, b, compare) {
var ha = a.head;
var hb = b.head;
var pa = ha;
var pb = hb;
var c = new List();
var q;
compare = compare || function (data1, data2) {
return data1 <= data2;
};

while (pa && pb) {
var data1 = pa.data;
var data2 = pb.data;

if (!compare(data1, data2)) {
// delete head node
q = a.delFirst();
// append the node to c linkedList
c.append(q);
pa = a.head;
} else {
q = b.delFirst();
c.append(q);
pb = b.head;
}
}

if (pa) {
c.append(pa);
} else {
c.append(pb);
}

return c;
};

List.prototype = {
makeNode: function(data, next){
return {
data: data != null ?  data : null,
next: next || null
};
},
delFirst: function () {
var head = this.head;
this.head = this.head.next;
head.next = null;

if(this.head === null) this.tail = null;
return head;
},
append: function (node) {
if (this.head !== null) {
this.tail.next = node;
this.tail = this.tail.next;
} else {
this.head = node;
this.tail = node;
}
},
add: function (data) {
if (this.head === null) {
this.head = this.makeNode(data);
this.tail = this.head;
} else {
this.tail.next = this.makeNode(data);
this.tail = this.tail.next;
}

this.tail.data = data;
},
'delete': function (data) {
var current = this.head;
var previous = this.head;
var elem;

while (current !== null) {
if (data === current.data) {
if (current === this.head) {
this.head = current.next;
elem =  current.data;
break;
}

if (current === this.tail) this.tail = previous;

previous.next = current.next;
elem =  current.data;
break;
}

previous = current;
current = current.next;
}

if(this.head === null) this.tail = null;

return elem ? elem : false;
},
insertAsFirst: function (data) {
var temp = this.makeNode(data);
temp.next = this.head;
this.head = temp;
},
insertAfter: function (target, data) {
var current = this.head;
while (current !== null) {
if (current.data === target) {
var temp = this.makeNode(data);
temp.next = current.next;

if (current === this.tail) this.tail = temp;

current.next = temp;
return;
}

current = current.next;
}
},
item: function (index) {
var current = this.head;

while (current !== null) {
if (--index === 0) return current;

current = current.next;
}

return null;
},
each: function (callback) {
var current = this.head;

while (current !== null) {
callback(current);
current = current.next;
}
},
orderInsert: function(data, cmp){
cmp = typeof cmp === 'function' ? cmp : function (a, b){
if(a > b)
return 1;
else if(a === b)
return 0;
else
return -1;
};
var previous = this.head;
var current = this.head;

if(current === null){
this.head = this.tail = this.makeNode(data);
return;
}

var me = this;
while(current){
var ret = cmp(data, current.data);
// 如果插入元素大于当前元素,准备下次遍历
if(ret > 0){
previous = current;
current = current.next;

// 如果等于,直接插入到后面
} else if(ret === 0){
return insertBetween(data, previous, current);

// 如果小于则插入到前节点和当前节点中
// 因为已经是排序了,所以不需要多余判断了
} else {
if(this.head === previous && previous === current){
return this.insertAsFirst(data);
} else {
return insertBetween(data, previous, current);
}
}
}

// 插入到最后一个结点
previous.next = this.makeNode(data);
this.tail = previous.next;

function insertBetween(data, a, b){
var temp = me.makeNode(data);
temp.next = b;
a.next = temp;
return true;
}
}
};
/*
var list = new List();
list.add('b');
list.insertAsFirst('a');
list.insertAfter('b', 'c');
console.log(list.item(2));
console.log(JSON.stringify(list));
list.each(function (node) {
if (node.data === 'b') {
console.log('get b in each');
}
});
list['delete']('c');
list['delete']('a');
console.log(list);

var list2 = new List();
list2.add('c');
list2.insertAsFirst('d');
list2.insertAfter('d', 'b');
console.log(JSON.stringify(list2));

var list3 = List.mergeList(list, list2);
console.log(list3);
*/
/*
var list = new List();

list.orderInsert('e');
list.orderInsert('b');
list.orderInsert('c');
list.orderInsert('a');
list.orderInsert('d');
list.orderInsert('f');
*/
}(this.module || this));


以下是对应的单元测试代码:

describe('linkedList tests', function(){

var list = new List();

it('should find the second item', function(){
list.add('b');
expect(list.head.data).toBe('b');
expect(list.tail.next).toBe(null);

list.insertAsFirst('a');
expect(list.head.data).toBe('a');
expect(list.head.next.data).toBe('b');

list.insertAfter('b', 'c');
expect(list.item(2).data).toBe('b');
expect(list.tail.data).toBe('c');
});

it('should remove one item', function(){
expect(list['delete']('c')).toBe(true);
list['delete']('a');
expect(list.head.data).toBe('b');
});

var list2 = new List();

it('should match the json', function(){
list2.add('c');
list2.insertAsFirst('d');
list2.insertAfter('d', 'b');
expect(JSON.stringify(list2)).toBe('{"head":{"data":"d","next":{"data":"b","next":{"data":"c","next":null}}},"tail":{"data":"c","next":null}}');
});

it('should merge the lists', function(){
var list3 = List.mergeList(list, list2);
expect(list3.head.data).toBe('d');
expect(list3.head.next.data).toBe('b');
expect(list3.head.next.next.data).toBe('c');
expect(list3.tail.data).toBe('b');
});
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: