JavaScript中的LinkedList,如何将更改附加到列表中?
我遇到了JavaScript中变量的引用问题,我一直在努力解决这个问题 我正在准备教授一门关于数据结构的课程,在至少10年没有看过材料之后,我正在复习这些材料 我在理论上知道链表,但出于某种原因,我很难想出能在JavaScript中实际工作的代码(我选择JavaScript是因为我的类最了解JavaScript) 这是我的代码:JavaScript中的LinkedList,如何将更改附加到列表中?,javascript,linked-list,Javascript,Linked List,我遇到了JavaScript中变量的引用问题,我一直在努力解决这个问题 我正在准备教授一门关于数据结构的课程,在至少10年没有看过材料之后,我正在复习这些材料 我在理论上知道链表,但出于某种原因,我很难想出能在JavaScript中实际工作的代码(我选择JavaScript是因为我的类最了解JavaScript) 这是我的代码: let LinkedList = { head: {}, tail: {} }; let Node = { data: {}, ne
let LinkedList = {
head: {},
tail: {}
};
let Node = {
data: {},
next: {}
}
function isObjectEmpty(obj1) {
return Object.keys(obj1).length === 0 && obj1.constructor === Object;
}
function count(node, counter) {
if (node.next) {
return 1 + count(node.next, counter);
}
return counter;
}
/**
* Adds data to LinkedList
* @param {LinkedList} list
* @param {Node} data
*/
function add_node(list, data) {
let temp = Object.assign({}, Node);
temp.data = data;
temp.next = {};
if (Object.keys(list.head).length === 0) {
list.head = temp;
list.tail = temp;
} else {
list.tail.next = temp;
list.tail = temp;
}
return list;
}
function insert(l, n, position) {
if (position <= 0) {
position = 0;
} else {
position = position - 1;
}
var list = Object.assign({}, l);
var node = Object.assign({}, Node);
node.data = n;
// this only counts elements on the list.
var elements = count(list.head, 0);
if (position > elements) {
return list;
}
var currentPosition = list.head;
var counter = 0;
while (!isObjectEmpty(currentPosition)) {
if (position === counter) {
var tmp = currentPosition;
currentPosition = node;
currentPosition.next = tmp.next;
return list;
}
currentPosition = currentPosition.next;
counter++;
}
return list;
}
// how to use the function
let songs = [
{id: '1', name: 'Kamikaze', artist: 'Eminem', releaseDate: '2018-08-31'},
{id: '2', name: 'despacito', artist: 'Luis Fonsi', releaseDate: '2018-08-31'},
{id: '3', name: 'La tortura', artist: 'Shakira', releaseDate: '2018-08-31'},
{id: '4', name: 'Roar', artist: 'Roar', releaseDate: '2018-08-31'},
];
let list = Object.assign({}, LinkedList);
songs.forEach((song) => {
add_node(list, song); // nothing special, just builds the linkedlist
});
list = insert(list, {id: '5', name: 'Havana', artist:'who knows', releaseDate:'2018-01-01'}, 3);
console.log(list); // new object isn't there.
您可以看到,我实际上正在成功地将新节点插入到我想要插入的位置
但是如果您console.log
查看list
结构,您将发现新插入的节点不存在
我不知道我在哪里失败了,也不知道为什么列表保留了旧的引用,而没有遵循新的“路径”
非常感谢任何指向正确方向的指针。两个问题。首先,您要替换节点,而不是严格地插入。我想您希望
.next
成为tmp
节点,而不是tmp.next
currentPosition.next = tmp;
其次,需要在插入点之前保留对节点的引用,以便可以将其next
值设置为新插入的节点:
previousNode.next = node //<- node being the one you're inserting
为了确保插入初始位置的安全性,我们必须能够设置
list.head
。否则,我们将设置上一个节点的next
属性。您可以使用没有对象的版本。分配并将对象作为列表和由相同命名函数创建的节点使用。这个函数可以在以后用实例化函数替换,以实现更OOP风格的方法
此方案将获取一个节点,并根据功能将其插入列表末尾或列表中的任何位置。如果列表中不存在节点,则会将其插入到链接列表的开头
函数链接列表(){
返回{head:null,tail:null};
}
功能节点(数据,下一步){
返回{data,next};
}
函数insertTail(列表,节点){
如果(列表标题){
list.tail.next=节点;
list.tail=list.tail.next;
}否则{
list.head=节点;
list.tail=节点;
}
退货清单;
}
函数insertPos(列表,节点,n){
var temp=列表头,
以前的
如果(!temp){
返回insertTail(列表、节点);
}
while(temp.next&&n--){
先前=温度;
温度=下一个温度;
}
node.next=temp;
previous.next=节点;
退货清单;
}
var songs=[{id:'1',名称:'Kamikaze',艺术家:'Eminem',发行日期:'2018-08-31'},{id:'2',名称:'despacito',艺术家:'Luis Fonsi',发行日期:'2018-08-31'},{id:'3',名称:'La tortura艺术家:'Shakira',发行日期:'2018-08-31'},{id:'4',名称:'Roar',艺术家:'Roar',发行日期:'2018-08-31'},
list=linkedList();
forEach(song=>insertTail(列表,节点(song));
控制台日志(列表);
insertPos(列表,节点({id:'5',名称:'Havana',艺术家:'who knows',发布日期:'2018-01-01'}),3);
控制台日志(列表)代码>
。作为控制台包装{最大高度:100%!重要;顶部:0;}
如果在此块中放置调试器:
if (position === counter) {
var tmp = currentPosition;
currentPosition = node;
currentPosition.next = tmp.next;
return list;
}
if (position === counter) {
var tmp = currentPosition;
currentPosition = node;
currentPosition.next = tmp.next;
return list;
}
您可以看到,我实际上成功地插入了新节点
我想去哪里
不,你没有。如果我们删除tmp
和currentPosition
赋值混淆,则该位代码相当于
if (position === counter) {
node.next = currentPosition.next;
return list;
}
所发生的一切是,您正在将列表的尾部复制到新节点上,但您从未真正将该节点作为列表中当前节点的下一个插入。少了一个
currentPosition.next = node;
还有几点:
- 不要使用
isObjectEmpty
和空对象来表示“无节点”。改用null
。如果出于某种说教性原因,您不想引入null
,请在对象上使用布尔.isNode
属性来区分包含数据的节点和空节点
- 避免
对象。分配。你的用法真的很不规范。在
let temp = Object.assign({}, Node);
temp.data = data;
temp.next = {};
您正在直接覆盖刚从节点复制的值
-最好简化为使用对象文字:
let temp = {data, next: {}};
在var list=Object.assign({},l)代码>您根本不想创建新对象。您将对传入列表进行变异,因此您应该保留该列表。(如果要使纯函数具有不可变的数据结构,则必须使所有节点也不可变,并将克隆插入整个列表直到所需位置)
- 如果
Object.assign
的目的是创建新对象,这些对象以后可能会涉及您不打算覆盖的其他属性(或方法),请改用factory函数
- 不要事先清点清单。一次完成插入,如果您到达列表末尾,位置变为惰性,则返回
函数makeLinkedList(){
返回{head:null,tail:null};
}
函数makeNode(数据,下一步=null){
返回{data,next};
}
函数追加(列表、节点){
如果(列表标题){
list.tail.next=节点;
}否则{
list.head=节点;
}
list.tail=节点;
}
函数插入(列表、数据、位置){
如果(位置<0)抛出新错误(“位置必须为非负”);
设newNode=makeNode(数据);
让prev=null,cur=list.head;
while(cur!=null&&position>0){
prev=cur;
cur=cur.next;
位置--;
}
如果(cur==null&&position>0)抛出新错误(“position必须是那些对象。assign
调用是伪造的,它不会克隆嵌套的对象。你能不能也添加一个例子,说明你将如何调用函数?什么是esObjetoVacio
?你不应该在那里检查null
吗?@Bergi I
let temp = {data, next: {}};
function makeLinkedList() {
return { head: null, tail: null };
}
function makeNode(data, next = null) {
return { data, next };
}
function append(list, node) {
if (list.head) {
list.tail.next = node;
} else {
list.head = node;
}
list.tail = node;
}
function insert(list, data, position) {
if (position < 0) throw new Error("position must be nonnegative");
let newNode = makeNode(data);
let prev = null, cur = list.head;
while (cur != null && position > 0) {
prev = cur;
cur = cur.next;
position--;
}
if (cur == null && position > 0) throw new Error("position must be <= list length")
if (cur == null) {
list.tail = newNode;
} else {
newNode.next = cur;
}
if (prev == null) {
list.head = newNode;
} else {
prev.next = newNode;
}
}