数据结构教程网盘链接_数据结构101:链接列表

数据结构教程网盘链接

by Kevin Turney

凯文·特尼(Kevin Turney)

Like stacks and queues, Linked Lists are a form of a sequential collection. It does not have to be in order. A Linked list is made up of independent nodes that may contain any type of data. Each node has a reference to the next node in the link.

堆栈队列一样 ,链接列表是顺序集合的一种形式。 它不一定是有序的。 链接列表由可能包含任何类型的数据的独立节点组成。 每个节点都有对链接中下一个节点的引用。

We can emulate stacks and queues with linked lists. We can as well use it as a base to create or augment other data structures. With linked lists, our primary concerns are with fast insertions and deletions, which are more performant over arrays.

我们可以使用链接列表来模拟堆栈和队列。 我们也可以将其用作创建或扩充其他数据结构的基础。 对于链表,我们的主要关注点是快速插入和删除,它们在数组上的性能更高。

The building block of this structure is a Node.

此结构的构建块是节点。

const Node = function(value) {  this.value = value;  this.next = null;};

Our Node is built with two properties, a value to hold data, and next, a reference initially set to null. The next property is used to “point” to the next Node in the linking. One of the disadvantages of linked lists is that each reference requires a larger memory overhead than an array.

我们的Node具有两个属性,一个用于保存数据的valuenext是最初设置为null的引用。 next属性用于“指向”链接中的下一个节点。 链表的缺点之一是每个引用比数组需要更大的内存开销。

实作 (Implementation)

const LinkedList = function(headvalue) {  // !! coerces a value to a Boolean  if (!!headvalue) {    return "Must provide an initial value for the first node"  } else {    this._head = new Node(headvalue);    this._tail = this.head;  }};

In our second constructor, we test for a value to provide for the first Node. If true, we proceed to create a new Node with the value passed and set the head to tail initially.

在第二个构造函数中,我们测试要提供给第一个Node的值。 如果为true,我们将继续使用传递的值创建一个新的Node,并将head最初设置为tail。

插入 (Insertion)
LinkedList.prototype.insertAfter = function(node, value) {  let newNode = new Node(value);  let oldNext = node.next;  newNode.next = oldNext;  node.next = newNode;  if (this._tail === node) {    this._tail = newNode;  }  return newNode;};

For this method, we create a new Node and adjust the references. The former next reference of the original node is now directed to newNode. The newNode’s next reference is “pointed” to what the previous node’s next was referring to. Finally, we check and reset the tail property.

对于此方法,我们创建一个新的Node并调整引用。 现在将原始节点的前一个下一个引用定向到newNode。 newNode的下一个引用“指向”上一个节点的下一个引用。 最后,我们检查并重置tail属性。

LinkedList.prototype.insertHead = function(value) {  let newHead = new Node(value);  let oldHead = this._head  newHead.next = oldHead;  this._head = newHead;  return this._head;};
LinkedList.prototype.appendToTail = function(value) {  let newTail = new Node(value);  this._tail.next = newTail;  this._tail = newTail;  return this._tail;};

Insertion at the beginning or end of a linked list is fast, operating in constant time. For this, we create a new node with a value and rearrange our reference variables. We reset the node which is now the head with insertHead or the tail with appendToTail.

快速插入链表的开头或结尾,并且操作时间固定。 为此,我们创建一个具有值的新节点,并重新排列参考变量。 我们将节点重置为现在的头,其头为insertHead或尾部为appendToTail

These operations represent fast insertions for collections, push for stacks, and enqueue for queues. It may come to mind that unshift for arrays is the same. No, because with unshift all members of the collection must be moved one index over. This makes it a linear time operation.

这些操作表示对集合的快速插入,对堆栈的推送以及对队列的排队。 可能会想到,数组的不变移位是相同的。 不可以,因为在取消移位时,必须将集合的所有成员移到一个索引上。 这使其成为线性时间操作。

删除中 (Deletion)
LinkedList.prototype.removeAfter = function(node) {  let removedNode = node.next;  if (!!removedNode) {    return "Nothing to remove"  } else {    let newNext = removedNode.next    node.next = newNext;    removedNode.next = null; // dereference to null to free up memory    if (this._tail === removedNode) {      this._tail = node;    }  }  return removedNode;};

Starting with a test for a node to remove, we proceed to adjust the references. Dereferencing the removedNode and setting it to null is important. This frees up memory and avoids having multiple references to the same object.

从测试要删除的节点开始,我们继续调整引用。 removedNode引用removedNode并将其设置为null很重要。 这样可以释放内存,并避免对同一对象有多个引用。

LinkedList.prototype.removeHead = function() {  let oldHead = this._head;  let newHead = this._head.next;  this._head = newHead;  oldHead.next = null;  return this._head;};

Deletion of a head and of a specified node in, removeAfter, are constant time removals. In addition, if the value of the tail is known, then tail removal can be done in O(1). Else we have to move linearly to the end to remove it, O(N);

删除头和指定节点中的removeAfter是恒定时间删除。 另外,如果知道尾巴的值,则可以在O(1)中进行尾巴去除。 否则,我们必须线性移动到最后才能将其删除,O(N);

循环播放 (Looping and forEach)

We use the following to iterate through a linked list or to operate on each node value.

我们使用以下内容迭代链接列表或对每个节点值进行操作。

LinkedList.prototype.findNode = function(value) {  let node = this._head;  while(node) {    if (node.value === value) {      return node;    }    node = node.next;  }  return `No node with ${value} found`;};
LinkedList.prototype.forEach = function(callback) {  let node = this._head;  while(node) {    callback(node.value);    node = node.next;  }};
LinkedList.prototype.print = function() {  let results = [];  this.forEach(function(value) {    result.push(value);  });  return result.join(', ');};

The main advantage of Linked Lists is fast insertions and deletions without rearranging items or reallocation of space. When we use an array, the memory space is contiguous, meaning we keep it all together. With linked lists, we can have memory spaces all over the place, non-contiguous storage through the use of references. For arrays, that locality of references means that arrays have better caching of values for faster lookup. With linked lists, caching is not optimized and access time takes longer.

链接列表的主要优点是快速插入和删除,而无需重新排列项目或重新分配空间。 当我们使用数组时,内存空间是连续的,这意味着我们将它们保持在一起。 使用链表,我们可以在各处拥有存储空间,通过使用引用可以实现非连续存储。 对于数组,引用的局部性意味着数组可以更好地缓存值以加快查找速度。 使用链接列表时,无法优化缓存,并且访问时间会更长。

Another aspect of linked lists is different types of configuration. Two primary examples are circularly linked, where the tail has a reference to the head and the head to the tail. Doubly linked is when, in addition to the node having a reference to the next node, also has a reference looking back to the previous node.

链表的另一方面是不同类型的配置。 两个主要的示例是循环链接的,其中,尾部引用了头部,头部引用了尾部。 链接是指除了该节点具有对下一个节点的引用之外,还具有回溯到前一个节点的引用。

时间复杂度 (Time Complexity)

Insertion

插入

  • insertHead, appendToTail — O(1)

    insertHead,appendToTail — O(1)
  • if a specific node is known, insertAfter — O(1)

    如果已知特定节点,则insertAfter — O(1)

Deletion

删除中

  • removeHead — O(1);

    removeHead — O(1);
  • if a specific node is known, removeAfter — O(1)

    如果已知特定节点,则removeAfter — O(1)
  • if the node is not known — O(N)

    如果节点未知— O(N)

Traversing

遍历

  • findNode, forEach, print — O(N)

    findNode,forEach,打印— O(N)

翻译自: https://www.freecodecamp.org/news/data-structures-101-linked-lists-254c82cf5883/

数据结构教程网盘链接

数组的插入:   #include   #define SIZE 10   int main()   {   int a[SIZE]={10,12,14,16,18,20,13,200,134,59}; /* 初始化数组 */   int b[SIZE+1]={0},i,j,x,v; /* b数组为插入后的数组,新插入了一个元素,所以要在原数组的基础上加1 */   printf(\"Please input insert addr:\");   scanf(\"%d\",&x); /* 插入值的位置 */   printf(\"Please input insert value:\");   scanf(\"%d\",&v); /* 插入值 */   for (i=0;ix) b[i+1]=a[i]; /* 当循环中的i大于插入值的位置x时,以后每一个元素所放的位置向后退一   格 */   if (i<x) b[i]=a[i]; /* 当循环中的i小于插入值的位置x时,每一个元素所放的位置不变 */   }   printf(\"This array is:n\");   for (j=0;j<=SIZE;j++)   printf(\"]\",b[j]); /* 打印数组 */   printf(\"n\");   return 0;   }   数组的删除:   #include   #define SIZE 10   int main()   {   int a[SIZE]={10,12,14,16,18,20,13,200,134,59};   int b[SIZE-1]={0},i,j,x,v;   printf(\"Please input insert addr:\");   scanf(\"%d\",&x);   for (i=0;ix) b[i-1]=a[i];   if (i<x) b[i]=a[i];   }   printf(\"This array is:n\");   for (j=0;j<=SIZE-2;j++)   printf(\"]\",b[j]);   printf(\"n\");   return 0;   }   数组的插入跟数组删除大体上差不多,当插入元素后,插入点后面的每一个元素向后移一个位置,而删除是向前移一个位置。   数组的排序(泡沫排序法):   /* 本程序把数组的值按升排列 */   #include   #define SIZE 15   main()   {   int a[SIZE]={900,2,3,58,34,76,32,43,56,70,35,234,532,543,2500};   int i,pass,hold,j=0,k=0;   printf(\"Data items in oraginal ordern\");   for (i=0;i<=SIZE-1;i++) /* 打印排序前的数组 */   printf(\"m\",a[i]);   for (pass=1;pass<=SIZE-1;pass++) { /* 比较的趟数 */   for (i=0;ia[i+1]) {   hold=a[i];   a[i]=a[i+1];   a[i+1]=hold;   }   }   }   printf(\"nData items in ascending ordern\");   for (i=0;i<=SIZE-1;i++) /* 打印排序后的数组 */   printf(\"m\",a[i]);   printf(\"n\");   return 0;   }   Come on!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值