wordlinking word什么意思

英语连读有哪些规则跟变音技巧呢?
按时间排序
我是英语老师,正在精心日更《新概念二册连读集(美音)》,基于经典教材将连读现象逐个击破。请关注我的日报:规律总结到处都能找到,不如实践来练习,你会享受语流中的各种奇妙语音组合。(其中一个快乐的事儿,是制作每课的动图哈哈)
来推广英音群楼上说的很赞,我补充一点点。1.如果前面一个词的结尾和下一个词的开头都是辅音,而且它们的发音部位接近的话,会发生合并(elision)的现象。例如:hot teadon't darered lion这里的 t 't d 都失去了声音。2.另外一个是 intrusive r。这在标准 RP 里是没有的,只存在于农村口音里。例如:Law (r) and orderThe idea (r) of it3.意群这个概念我想有点过大,很难把握。一般来说也就是以下的几个 pattern。(1) 复合名词tennis court,dish washer,golf club(2) 动词词组speak up,get down,walk away(3) 动词ing词组generally speaking,good looking,agree unanimously(4) 介词词组in addition,from London,in town以上这几个 pattern 要把它们当做一个词读,不要拆开,因此要使用连音(liaison)。P.S. 至于 vowel to vowel 的情况,没有必要刻意添加 w 和 j,如果你能发准前后的两个元音,中间的这个半元音(w和j)会自动出现,刻意添加显得太油(比如美国人)
(本答案理论部分适用于识音标者。不认识音标的话,请直接看最后个人经验。虽然那些差不多都是废话。)(本答案中“-”表示连读)(本答案为鹰语系专业课语音书理论,内容比较枯燥。提前给能坚持从头看到尾的人点个赞。)There are three kinds of word linking:1.linking final consonant sounds to initial vowel sounds前一个单词以辅音结尾,后一个单词以元音开头for example: read- think-of- a cup-of tea2.r-linkingIn a sense group if the preceding word ends with the letter "r" and the following word starts with a vowel sound, then "r" is usually pronounced.以辅音字母r或re结尾的单词与紧跟其后的单词词首元音相连时必须保留r或re的发音。(例如ear中的r的发音和read中的r的发音方式是不一样的,实在不知道怎么讲只能说前者类似于“额”的发音后者类似于“弱”的发音方式,两字均念轻声!这一点中就需要将前一种发音变为后一种发音来与后一个单词的开头元音连起来念)for example: read after- over-and over- more-or less3.linking final vowel sounds to initial vowel soundsThere are two cases for linking between vowels:①When a word ending with the front vowels /i:
I/ or with the diphthongs /ei
?i/ is followed by a word starting with any vowel sound, a gentle /j/ is used to linked the two.当前一词词尾为元音/i:
?i/时,它与后面词首的元音连读时,它们之间好像加了个/j/for example: my-eyes /mai-jaiz/ ; the-old /?l-j?ud/ ; grey-and blue /grei-j?nd blu:/②When a word ending with the back vowels /u:
u/ or with the diphthongs /?u
au/ is followed by a word starting with any vowel sound, a gentle /w/ is used wo link the two.当前一词词尾为/u:
au/时,它与后面词首的元音连读时,它们之间好像加了个/w/ for example: to ask /tu-wa:sk/ ; to answer /tu-wa:ns?/——但是在连读中要知道英语中的意群(sense group)的定义。意群就是指句子中按意思和结构划分出的各个成分,每一个成分即称为一个意群。同一意群中的词与词的关系紧密相关,密不可分。For example: A long sentence / can be cut up / into two or more tone groups. 这句句子可以被划分为三个意群。——大多数连读只在意群之间发生,但在较快的语流中,如果句子不长,意群与意群之间也可以连读。For example: Please write-in-English
and give-it to the-air hostess
before we land.(此句中空格较大的部分表示意群的划分)注意此句中the air 部分,由于air是由元音开头,这种单词前面的the要弱读为/?i/ ,此处的连读现象参照第3点①。——一般情况下,句子越长越复杂,中间的停顿也就越多越长,以便给听众足够的时间去理解和思考。停顿时一定要用降升调和升调提醒观众话还未完(作为一个鹰语系学生降升调也是个挑战……可以忽略降升调。)。以下为个 (yi) 人 (dui) 经 (fei) 验 (hua) :其实只要把每个词都发准确(我不是指把每个单词里面的每个音都发出来,很多单词是有爆破现象的,这个说起来内容太多了。只能说是发音方式要准确该发音的地方发到位。至于要问怎么全部发到位那么就要开始系统的学语音了。),然后适当的语速加快,多练多听多读很容易就找到感觉连起来了。或者多听多注意native speaker是怎么说的也可以模仿。至于意群,其实就是在你感觉一个句子的一个完整的部分已经说完了之后作适当停顿,自然也就没有连读了。其实英语这个东西,理论没有太大的作用,主要还是多接触多听多说。就像我们的中文也不是靠理论学起来的,多听身边的人怎么说自然就学会了。像在我们鹰语系里大家同时学语音理论,但是有的人在学理论之前就可以自然地(下意识地)连读但是有的人学过理论之后还是不能很好地运用。这些还是要靠慢慢积累。还有,千万不要为了听起来高大上而连读,先确保自己读的清晰别人能听得懂。不然整个句子整篇文章全部连在一起会把人逼疯的。
已有帐号?
无法登录?
社交帐号登录From Wikipedia, the free encyclopedia
In , a linked list is a linear collection of data elements, called nodes pointing to the next node by means of a pointer. It is a
consisting of a group of
which together represent a . Under the simplest form, each node is composed of data and a
(in other words, a link) to the next
more complex variants add additional links. This structure allows for efficient insertion or removal of elements from any position in the sequence.
A linked list whose nodes contain two fields: an integer value and a link to the next node. The last node is linked to a terminator used to signify the end of the list.
Linked lists are among the simplest and most common data structures. They can be used to implement several other common , including
(the abstract data type), , , , and , though it is not uncommon to implement the other data structures directly without using a list as the basis of implementation.
The principal benefit of a linked list over a conventional
is that the list elements can easily be inserted or removed without reallocation or reorganization of the entire structure because the data items need not be stored contiguously in memory or on disk, while an array has to be declared in the source code, before compiling and running the program. Linked lists allow insertion and removal of nodes at any point in the list, and can do so with a constant number of operations if the link previous to the link being added or removed is maintained during list traversal.
On the other hand, simple linked lists by themselves do not allow
to the data, or any form of efficient indexing. Thus, many basic operations — such as obtaining the last node of the list (assuming that the last node is not maintained as separate node reference in the list structure), or finding a node that contains a given datum, or locating the place where a new node should be inserted — may require sequential scanning of most or all of the list elements. The advantages and disadvantages of using linked lists are given below.
Linked lists are a dynamic data structure, which can grow and be pruned, allocating and deallocating memory while the program is running.
Insertion and deletion node operations are easily implemented in a linked list.
Linear data structures such as stacks and queues are easily executed with a linked list.
They can reduce access time and may expand in real time without memory overhead.
They use more memory than
because of the storage used by their .
Nodes in a linked list must be read in order from the beginning as linked lists are inherently .
Nodes are stored incontiguously, greatly increasing the time required to access individual elements within the list.
Difficulties arise in linked lists when it comes to reverse traversing. For instance, singly linked lists are cumbersome to navigate backwards and while doubly linked lists are somewhat easier to read, memory is wasted in allocating space for a back pointer.
Linked lists were developed in
as the primary
for their . IPL was used by the authors to develop several early
programs, including the Logic Theory Machine, the , and a computer chess program. Reports on their work appeared in IRE Transactions on Information Theory in 1956, and several conference proceedings from 1957 to 1959, including Proceedings of the Western Joint Computer Conference in 1957 and 1958, and Information Processing (Proceedings of the first
International Conference on Information Processing) in 1959. The now-classic diagram consisting of blocks representing list nodes with arrows pointing to successive list nodes appears in "Programming the Logic Theory Machine" by Newell and Shaw in Proc. WJCC, February 1957. Newell and Simon were recognized with the ACM
in 1975 for having "made basic contributions to artificial intelligence, the psychology of human cognition, and list processing". The problem of
processing led
(MIT) to use linked lists as data structures in his COMIT programming language for computer research in the field of . A report on this language entitled "A programming language for mechanical translation" appeared in Mechanical Translation in 1958.
, standing for list processor, was created by
in 1958 while he was at MIT and in 1960 he published its design in a paper in the , entitled "Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I". One of LISP's major data structures is the linked list.
By the early 1960s, the utility of both linked lists and languages which use these structures as their primary data representation was well established. Bert Green of the
published a review article entitled "Computer languages for symbol manipulation" in IRE Transactions on Human Factors in Electronics in March 1961 which summarized the advantages of the linked list approach. A later review article, "A Comparison of list-processing computer languages" by Bobrow and Raphael, appeared in Communications of the ACM in April 1964.
Several operating systems developed by
(originally of West Lafayette Indiana, and later of Chapel Hill, North Carolina) used singly linked lists as file structures. A directory entry pointed to the first sector of a file, and succeeding portions of the file were located by traversing pointers. Systems using this technique included Flex (for the
CPU), mini-Flex (same CPU), and Flex9 (for the Motorola 6809 CPU). A variant developed by TSC for and marketed by Smoke Signal Broadcasting in California, used doubly linked lists in the same manner.
The TSS/360 operating system, developed by IBM for the System 360/370 machines, used a double linked list for their file system catalog. The directory structure was similar to Unix, where a directory could contain files and other directories and extend to any depth.
Each record of a linked list is often called an 'element' or ''.
The field of each node that contains the address of the next node is usually called the 'next link' or 'next pointer'. The remaining fields are known as the 'data', 'information', 'value', 'cargo', or 'payload' fields.
The 'head' of a list is its first node. The 'tail' of a list may refer either to the rest of the list after the head, or to the last node in the list. In
and some derived languages, the next node may be called the '' (pronounced could-er) of the list, while the payload of the head node may be called the 'car'.
Singly linked lists contain nodes which have a data field as well as a 'next' field, which points to the next node in line of nodes. Operations that can be performed on singly linked lists include insertion, deletion and traversal.
A singly linked list whose nodes contain two fields: an integer value and a link to the next node
Main article:
In a 'doubly linked list', each node contains, besides the next-node link, a second link field pointing to the 'previous' node in the sequence. The two links may be called 'forward('s') and 'backwards', or 'next' and 'prev'('previous').
A doubly linked list whose nodes contain three fields: an integer value, the link forward to the next node, and the link backward to the previous node
A technique known as
allows a doubly linked list to be implemented using a single link field in each node. However, this technique requires the ability to do bit operations on addresses, and therefore may not be available in some high-level languages.
Many modern operating systems use doubly linked lists to maintain references to active processes, threads, and other dynamic objects. A common strategy for
to evade detection is to unlink themselves from these lists.
In a 'multiply linked list', each node contains two or more link fields, each field being used to connect the same set of data records in a different order (e.g., by name, by department, by date of birth, etc.). While doubly linked lists can be seen as special cases of multiply linked list, the fact that the two orders are opposite to each other leads to simpler and more efficient algorithms, so they are usually treated as a separate case.
In the last
of a list, the link field often contains a
reference, a special value used to indicate the lack of further nodes. A less common convention is to make it point to the fi in that case the list is said to be 'circular' or 'circularly linked'; otherwise it is said to be 'open' or 'linear'.
A circular linked list
In the case of a circular doubly linked list, the only change that occurs is that the end, or "tail", of the said list is linked back to the front, or "head", of the list and vice versa.
Main article:
In some implementations an extra 'sentinel' or 'dummy' node may be added before the first data record or after the last one. This convention simplifies and accelerates some list-handling algorithms, by ensuring that all links can be safely dereferenced and that every list (even one that contains no data elements) always has a "first" and "last" node.
An empty list is a list that contains no data records. This is usually the same as saying that it has zero nodes. If sentinel nodes are being used, the list is usually said to be empty when it has only sentinel nodes.
The link fields need not be physically part of the nodes. If the data records are stored in an array and referenced by their indices, the link field may be stored in a separate array with the same indices as the data records.
Since a reference to the first node gives access to the whole list, that reference is often called the 'address', 'pointer', or 'handle' of the list. Algorithms that manipulate linked lists usually get such handles to the input lists and return the handles to the resulting lists. In fact, in the context of such algorithms, the word "list" often means "list handle". In some situations, however, it may be convenient to refer to a list by a handle that consists of two links, pointing to its first and last nodes.
The alternatives listed above may be arbitrarily combined in almost every way, so one may have circular doubly linked lists without sentinels, circular singly linked lists with sentinels, etc.
As with most choices in computer programming and design, no method is well suited to all circumstances. A linked list data structure might work well in one case, but cause problems in another. This is a list of some of the common tradeoffs involving linked list structures.
Comparison of list data structures
Linked list
Insert/delete at beginning
Insert/delete at end
Θ(n) when last element is unknown;
Θ(1) when last element is known
Θ(log n) updating
Insert/delete in middle
search time + Θ(1)
Θ(log n) updating
Wasted space (average)
is a data structure that allocates all elements contiguously in memory, and keeps a count of the current number of elements. If the space reserved for the dynamic array is exceeded, it is reallocated and (possibly) copied, an expensive operation.
Linked lists have several advantages over dynamic arrays. Insertion or deletion of an element at a specific point of a list, assuming that we have indexed a pointer to the node (before the one to be removed, or before the insertion point) already, is a constant-time operation (otherwise without this reference it is O(n)), whereas insertion in a dynamic array at random locations will require moving half of the elements on average, and all the elements in the worst case. While one can "delete" an element from an array in constant time by somehow marking its slot as "vacant", this causes
that impedes the performance of iteration.
Moreover, arbitrarily many elements may be inserted into a linked list, limited only by the to while a dynamic array will eventually fill up its underlying array data structure and will have to reallocate — an expensive operation, one that may not even be possible if memory is fragmented, although the cost of reallocation can be averaged over insertions, and the cost of an insertion due to reallocation would still be
O(1). This helps with appending elements at the array's end, but inserting into (or removing from) middle positions still carries prohibitive costs due to data moving to maintain contiguity. An array from which many elements are removed may also have to be resized in order to avoid wasting too much space.
On the other hand, dynamic arrays (as well as fixed-size ) allow constant-time , while linked lists allow only
to elements. Singly linked lists, in fact, can be easily traversed in only one direction. This makes linked lists unsuitable for applications where it's useful to look up an element by its index quickly, such as . Sequential access on arrays and dynamic arrays is also faster than on linked lists on many machines, because they have optimal
and thus make good use of data caching.
Another disadvantage of linked lists is the extra storage needed for references, which often makes them impractical for lists of small data items such as
or , because the storage overhead for the links may exceed by a factor of two or more the size of the data. In contrast, a dynamic array requires only the space for the data itself (and a very small amount of control data). It can also be slow, and with a na?ve allocator, wasteful, to allocate memory separately for each new element, a problem generally solved using .
Some hybrid solutions try to combine the advantages of the two representations.
store several elements in each list node, increasing cache performance while decreasing memory overhead for references.
does both these as well, by replacing references with the actual data referenced, which extends off the end of the referencing record.
A good example that highlights the pros and cons of using dynamic arrays vs. linked lists is by implementing a program that resolves the . The Josephus problem is an election method that works by having a group of people stand in a circle. Starting at a predetermined person, you count around the circle n times. Once you reach the nth person, take them out of the circle and have the members close the circle. Then count around the circle the same n times and repeat the process, until only one person is left. That person wins the election. This shows the strengths and weaknesses of a linked list vs. a dynamic array, because if you view the people as connected nodes in a circular linked list then it shows how easily the linked list is able to delete nodes (as it only has to rearrange the links to the different nodes). However, the linked list will be poor at finding the next person to remove and will need to search through the list until it finds that person. A dynamic array, on the other hand, will be poor at deleting nodes (or elements) as it cannot remove one node without individually shifting all the elements up the list by one. However, it is exceptionally easy to find the nth person in the circle by directly referencing them by their position in the array.
problem concerns the efficient conversion of a linked list representation into an array. Although trivial for a conventional computer, solving this problem by a
is complicated and has been the subject of much research.
has similar memory access patterns and space overhead to a linked list while permitting much more efficient indexing, taking O(log n) time instead of O(n) for a random access. However, insertion and deletion operations are more expensive due to the overhead of tree manipulations to maintain balance. Schemes exist for trees to automatically maintain themselves in a balanced state:
While doubly linked and circular lists have advantages over singly linked linear lists, linear lists offer some advantages that make them preferable in some situations.
A singly linked linear list is a
data structure, because it contains a pointer to a smaller object of the same type. For that reason, many operations on singly linked linear lists (such as
two lists, or enumerating the elements in reverse order) often have very simple recursive algorithms, much simpler than any solution using . While those recursive solutions can be adapted for doubly linked and circularly linked lists, the procedures generally need extra arguments and more complicated base cases.
Linear singly linked lists also allow , the use of a common final portion of sub-list as the terminal portion of two different lists. In particular, if a new node is added at the beginning of a list, the former list remains available as the tail of the new one — a simple example of a . Again, this is not true with the other variants: a node may never belong to two different circular or doubly linked lists.
In particular, end-sentinel nodes can be shared among singly linked non-circular lists. The same end-sentinel node may be used for every such list. In , for example, every proper list ends with a link to a special node, denoted by nil or (), whose
and CDR links point to itself. Thus a Lisp procedure can safely take the CAR or CDR of any list.
The advantages of the fancy variants are often limited to the complexity of the algorithms, not in their efficiency. A circular list, in particular, can usually be emulated by a linear list together with two variables that point to the first and last nodes, at no extra cost.
Double-linked lists require more space per node (unless one uses ), and their elementary operation but they are often easier to manipulate because they allow fast and easy sequential access to the list in both directions. In a doubly linked list, one can insert or delete a node in a constant number of operations given only that node's address. To do the same in a singly linked list, one must have the address of the pointer to that node, which is either the handle for the whole list (in case of the first node) or the link field in the previous node. Some algorithms require access in both directions. On the other hand, doubly linked lists do not allow tail-sharing and cannot be used as .
A circularly linked list may be a natural option to represent arrays that are naturally circular, e.g. the corners of a , a pool of
that are used and released in
("first in, first out") order, or a set of processes that should be
in . In these applications, a pointer to any node serves as a handle to the whole list.
With a circular list, a pointer to the last node gives easy access also to the first node, by following one link. Thus, in applications that require access to both ends of the list (e.g., in the implementation of a queue), a circular structure allows one to handle the structure by a single pointer, instead of two.
A circular list can be split into two circular lists, in constant time, by giving the addresses of the last node of each piece. The operation consists in swapping the contents of the link fields of those two nodes. Applying the same operation to any two nodes in two distinct lists joins the two list into one. This property greatly simplifies some algorithms and data structures, such as the
The simplest representation for an empty circular list (when such a thing makes sense) is a null pointer, indicating that the list has no nodes. Without this choice, many algorithms have to test for this special case, and handle it separately. By contrast, the use of null to denote an empty linear list is more natural and often creates fewer special cases.
may simplify certain list operations, by ensuring that the next or previous nodes exist for every element, and that even empty lists have at least one node. One may also use a sentinel node at the end of the list, with an appropriate data field, to eliminate some end-of-list tests. For example, when scanning the list looking for a node with a given value x, setting the sentinel's data field to x makes it unnecessary to test for end-of-list inside the loop. Another example is the merging two sorted lists: if their sentinels have data fields set to +∞, the choice of the next output node does not need special handling for empty lists.
However, sentinel nodes use up extra space (especially in applications that use many short lists), and they may complicate other operations (such as the creation of a new empty list).
However, if the circular list is used merely to simulate a linear list, one may avoid some of this complexity by adding a single sentinel node to every list, between the last and the first data nodes. With this convention, an empty list consists of the sentinel node alone, pointing to itself via the next-node link. The list handle should then be a pointer to the last data node, before the sentinel, if t or to the sentinel itself, if the list is empty.
The same trick can be used to simplify the handling of a doubly linked linear list, by turning it into a circular doubly linked list with a single sentinel node. However, in this case, the handle should be a single pointer to the dummy node itself.
When manipulating linked lists in-place, care must be taken to not use values that you have invalidated in previous assignments. This makes algorithms for inserting or deleting linked list nodes somewhat subtle. This section gives
for adding or removing nodes from singly, doubly, and circularly linked lists in-place. Throughout we will use null to refer to an end-of-list marker or , which may be implemented in a number of ways.
Our node data structure will have two fields. We also keep a variable firstNode which always points to the first node in the list, or is null for an empty list.
record Node
// The data being stored in the node
Node next // A
to the next node, null for last node
record List
Node firstNode // points t null for empty list
Traversal of a singly linked list is simple, beginning at the first node and following each next link until we come to the end:
node := list.firstNode
while node not null
(do something with node.data)
node := node.next
The following code inserts a node after an existing node in a singly linked list. The diagram shows how it works. Inserting a node before an existing one can instead, one must keep track of the previous node and insert a node after it.
function insertAfter(Node node, Node newNode) // insert newNode after node
newNode.next := node.next
:= newNode
Inserting at the beginning of the list requires a separate function. This requires updating firstNode.
function insertBeginning(List list, Node newNode) // insert node before current first node
newNode.next
:= list.firstNode
list.firstNode := newNode
Similarly, we have functions for removing the node after a given node, and for removing a node from the beginning of the list. The diagram demonstrates the former. To find and remove a particular node, one must again keep track of the previous element.
function removeAfter(Node node) // remove node past this one
obsoleteNode := node.next
node.next := node.next.next
destroy obsoleteNode
function removeBeginning(List list) // remove first node
obsoleteNode := list.firstNode
list.firstNode := list.firstNode.next // point past deleted node
destroy obsoleteNode
Notice that removeBeginning() sets list.firstNode to null when removing the last node in the list.
Since we can't iterate backwards, efficient insertBefore or removeBefore operations are not possible.
Appending one linked list to another can be inefficient unless a reference to the tail is kept as part of the List structure, because we must traverse the entire first list in order to find the tail, and then append the second list to this. Thus, if two linearly linked lists are each of length , list appending has
of . In the Lisp family of languages, list appending is provided by the
procedure.
Many of the special cases of linked list operations can be eliminated by including a dummy element at the front of the list. This ensures that there are no special cases for the beginning of the list and renders both insertBeginning() and removeBeginning() unnecessary. In this case, the first useful data in the list will be found at list.firstNode.next.
In a circularly linked list, all nodes are linked in a continuous circle, without using null. For lists with a front and a back (such as a queue), one stores a reference to the last node in the list. The next node after the last node is the first node. Elements can be added to the back of the list and removed from the front in constant time.
Circularly linked lists can be either singly or doubly linked.
Both types of circularly linked lists benefit from the ability to traverse the full list beginning at any given node. This often allows us to avoid storing firstNode and lastNode, although if the list may be empty we need a special representation for the empty list, such as a lastNode variable which points to some node in the list or is null if it' we use such a lastNode here. This representation significantly simplifies adding and removing nodes with a non-empty list, but empty lists are then a special case.
Assuming that someNode is some node in a non-empty circular singly linked list, this code iterates through that list starting with someNode:
function iterate(someNode)
if someNode ≠ null
node := someNode
do something with node.value
node := node.next
while node ≠ someNode
Notice that the test "while node ≠ someNode" must be at the end of the loop. If the test was moved to the beginning of the loop, the procedure would fail whenever the list had only one node.
This function inserts a node "newNode" into a circular linked list after a given node "node". If "node" is null, it assumes that the list is empty.
function insertAfter(Node node, Node newNode)
if node = null
newNode.next := newNode
newNode.next := node.next
node.next := newNode
Suppose that "L" is a variable pointing to the last node of a circular linked list (or null if the list is empty). To append "newNode" to the end of the list, one may do
insertAfter(L, newNode)
L := newNode
To insert "newNode" at the beginning of the list, one may do
insertAfter(L, newNode)
if L = null
L := newNode
Languages that do not support any type of
can still create links by replacing pointers with array indices. The approach is to keep an
of , where each record has integer fields indicating the index of the next (and possibly previous) node in the array. Not all nodes in the array need be used. If records are also not supported,
can often be used instead.
As an example, consider the following linked list record that uses arrays instead of pointers:
record Entry {
integer // index of next entry in array
integer // previous entry (if double-linked)
A linked list can be build by creating an array of these structures, and an integer variable to store the index of the first element.
integer listHead
Entry Records[1000]
Links between elements are formed by placing the array index of the next (or previous) cell into the Next or Prev field within a given element. For example:
Jones, John
Smith, Joseph
2 (listHead)
Adams, Adam
Ignore, Ignatius
Another, Anita
In the above example, ListHead would be set to 2, the location of the first entry in the list. Notice that entry 3 and 5 through 7 are not part of the list. These cells are available for any additions to the list. By creating a ListFree integer variable, a
could be created to keep track of what cells are available. If all entries are in use, the size of the array would have to be increased or some elements would have to be deleted before new entries could be stored in the list.
The following code would traverse the list and display names and account balance:
i := listHead
while i ≥ 0 // loop through the list
print i, Records[i].name, Records[i].balance // print entry
i := Records[i].next
When faced with a choice, the advantages of this approach include:
The linked list is relocatable, meaning it can be moved about in memory at will, and it can also be quickly and directly
for storage on disk or transfer over a network.
Especially for a small list, array indexes can occupy significantly less space than a full pointer on many architectures.
can be improved by keeping the nodes together in memory and by periodically rearranging them, although this can also be done in a general store.
can produce an excessive amount of overhead storage for almost no allocation overhead is incurred per node in this approach.
Seizing an entry from a pre-allocated array is faster than using dynamic memory allocation for each node, since dynamic memory allocation typically requires a search for a free memory block of the desired size.
This approach has one main disadvantage, however: it creates and manages a private memory space for its nodes. This leads to the following issues:
It increases complexity of the implementation.
Growing a large array when it is full may be difficult or impossible, whereas finding space for a new linked list node in a large, general memory pool may be easier.
Adding elements to a dynamic array will occasionally (when it is full) unexpectedly take linear ((n)) instead of constant time (although it's still an
constant).
Using a general memory pool leaves more memory for other data if the list is smaller than expected or if many nodes are freed.
For these reasons, this approach is mainly used for languages that do not support dynamic memory allocation. These disadvantages are also mitigated if the maximum size of the list is known at the time the array is created.
have singly linked lists built in. In many , these lists are constructed from nodes, each called a
or cons cell. The cons has two fields: the , a reference to the data for that node, and the , a reference to the next node. Although cons cells can be used to build other data structures, this is their primary purpose.
In languages that support
or templates, linked list ADTs or templates are available for building linked lists. In other languages, linked lists are typically built using
together with .
When constructing a linked list, one is faced with the choice of whether to store the data of the list directly in the linked list nodes, called internal storage, or merely to store a reference to the data, called external storage. Internal storage has the advantage of making access to the data more efficient, requiring less storage overall, having better , and simplifying memory management for the list (its data is allocated and deallocated at the same time as the list nodes).
External storage, on the other hand, has the advantage of being more generic, in that the same data structure and machine code can be used for a linked list no matter what the size of the data is. It also makes it easy to place the same data in multiple linked lists. Although with internal storage the same data can be placed in multiple lists by including multiple next references in the node data structure, it would then be necessary to create separate routines to add or delete cells based on each field. It is possible to create additional linked lists of elements that use internal storage by using external storage, and having the cells of the additional linked lists store references to the nodes of the linked list containing the data.
In general, if a set of data structures needs to be included in linked lists, external storage is the best approach. If a set of data structures need to be included in only one linked list, then internal storage is slightly better, unless a generic linked list package using external storage is available. Likewise, if different sets of data that can be stored in the same data structure are to be included in a single linked list, then internal storage would be fine.
Another approach that can be used with some languages involves having different data structures, but all have the initial fields, including the next (and prev if double linked list) references in the same location. After defining separate structures for each type of data, a generic structure can be defined that contains the minimum amount of data shared by all the other structures and contained at the top (beginning) of the structures. Then generic routines can be created that use the minimal structure to perform linked list type operations, but separate routines can then handle the specific data. This approach is often used in message parsing routines, where several types of messages are received, but all start with the same set of fields, usually including a field for message type. The generic routines are used to add new messages to a queue when they are received, and remove them from the queue in order to process the message. The message type field is then used to call the correct routine to process the specific type of message.
Suppose you wanted to create a linked list of families and their members. Using internal storage, the structure might look like the following:
record member { // member of a family
string firstN
record family { // the family itself
string lastN
member members // head of list of members of this family
To print a complete list of families and their members using internal storage, we could write:
aFamily := Families // start at head of families list
while aFamily ≠ null // loop through list of families
print information about family
aMember := aFamily.members // get head of list of this family's members
while aMember ≠ null // loop through list of members
print information about member
aMember := aMember.next
aFamily := aFamily.next
Using external storage, we would create the following structures:
record node { // generic link structure
pointer data // generic pointer for data at node
record member { // structure for family member
string firstN
integer age
record family { // structure for family
string lastN
node members // head of list of members of this family
To print a complete list of families and their members using external storage, we could write:
famNode := Families // start at head of families list
while famNode ≠ null // loop through list of families
aFamily := (family) famNode.data // extract family from node
print information about family
memNode := aFamily.members // get list of family members
while memNode ≠ null // loop through list of members
aMember := (member)memNode.data // extract member from node
print information about member
memNode := memNode.next
famNode := famNode.next
Notice that when using external storage, an extra step is needed to extract the record from the node and cast it into the proper data type. This is because both the list of families and the list of members within the family are stored in two linked lists using the same data structure (node), and this language does not have parametric types.
As long as the number of families that a member can belong to is known at compile time, internal storage works fine. If, however, a member needed to be included in an arbitrary number of families, with the specific number known only at run time, external storage would be necessary.
Finding a specific element in a linked list, even if it is sorted, normally requires O(n) time (). This is one of the primary disadvantages of linked lists over other data structures. In addition to the variants discussed above, below are two simple ways to improve search time.
In an unordered list, one simple heuristic for decreasing average search time is the move-to-front heuristic, which simply moves an element to the beginning of the list once it is found. This scheme, handy for creating simple caches, ensures that the most recently used items are also the quickest to find again.
Another common approach is to "" a linked list using a more efficient external data structure. For example, one can build a
whose elements are references to the linked list nodes. Multiple such indexes can be built on a single list. The disadvantage is that these indexes may need to be updated each time a node is added or removed (or at least, before that index is used again).
is a list with support for fast random access to read or modify any element in the list. One possible implementation is a
using the , which involves a list of trees wit this allows worst-case constant time head/cons operations, and worst-case logarithmic time random access to an element by index. Random access lists can be implemented as .
Random access lists can be viewed as immutable linked lists in that they likewise support the same O(1) head and tail operations.
A simple extension to random access lists is the , which provides an additional operation that yields the minimum element in the entire list in constant time (without[] mutation complexities).
are often implemented using linked lists, and simply restrict the type of operations which are supported.
is a linked list augmented with layers of pointers for quickly jumping over large numbers of elements, and then descending to the next layer. This process continues down to the bottom layer, which is the actual list.
can be seen as a type of linked list where the elements are themselves linked lists of the same nature. The result is that each node may include a reference to the first node of one or two other linked lists, which, together with their contents, form the subtrees below that node.
is a linked list in which each node contains an array of data values. This leads to improved cache performance, since more list elements are contiguous in memory, and reduced memory overhead, because less metadata needs to be stored for each element of the list.
may use linked lists to store the chains of items that hash to the same position in the hash table.
shares some of the ordering properties of a linked list, but is almost always implemented using an array. Instead of references from node to node, the next and previous data indexes are calculated using the current data's index.
rearranges its nodes based on some heuristic which reduces search times for data retrieval by keeping commonly accessed nodes at the head of the list.
The amount of control data required for a dynamic array is usually of the form , where
is a per-array constant,
is a per-dimension constant, and
is the number of dimensions.
are typically on the order of 10 bytes.
Skiena, Steven S. (2009).
(2nd ed.). Springer. p. 76.  . We can do nothing without this list predecessor, and so must spend linear time searching for it on a singly-linked list.
Chris Okasaki (1995). "Purely Functional Random-Access Lists". Proceedings of the Seventh International Conference on Functional Programming Languages and Computer Architecture: 86–95. :.
Gerald Kruse. : . Juniata College. Spring 2008.
at GoingNative 2012 on
from minute 45 or foil 44
Brodnik, A Carlsson, S ; Munro, JI; Demaine, ED (1999),
(PDF), Department of Computer Science, University of Waterloo
Ford, W Topp, William (2002). Data Structures with C++ using STL (Second ed.). Prentice-Hall. pp. 466–467.  .
Okasaki, Chris (1995).
(PS). In Functional Programming Languages and Computer Architecture (ACM Press). pp. 86–95 2015.
Juan, Angel (2006).
(PDF). p. 3.
Black, Paul E. (). Pieterse, V Black, Paul E., eds. . Dictionary of Algorithms and Data Structures. .
Antonakos, James L.; Mansfield, Kenneth C., Jr. (1999). Practical Data Structures Using C/C++. Prentice-Hall. pp. 165–190.  .
Collins, William J. (2005) [2002]. Data Structures and the Java Collections Framework. New York: McGraw Hill. pp. 239–303.  .
(2003). . MIT Press. pp. 205–213,501–505.  .
(2001). "10.2: Linked lists".
(2nd ed.). MIT Press. pp. 204–209.  .
Green, Bert F., Jr. (1961). "Computer Languages for Symbol Manipulation". IRE Transactions on Human Factors in Electronics (2): 3–8. :.
3 (4): 184. :.
(1997). "2.2.3-2.2.5". Fundamental Algorithms (3rd ed.). Addison-Wesley. pp. 254–298.  .
; Shaw, F. C. (1957). "Programming the Logic Theory Machine". Proceedings of the Western Joint Computer Conference: 230–240.
Parlante, Nick (2001).
(PDF). Stanford University.
(1998). Algorithms in C. Addison Wesley. pp. 90–109.  .
Shaffer, Clifford A. (1998). A Practical Introduction to Data Structures and Algorithm Analysis. New Jersey: Prentice Hall. pp. 77–102.  .
(1964). "An Experiment with a Self-compiling Compiler for a Simple List-Processing Language". Annual Review in Automatic Programming (Pergamon Press) 4 (1): 1. :.
(1964). "Lists and Why They are Useful". Proceeds of the ACM National Conference, Philadelphia 1964 (ACM) (P–64): F1–1.
Shanmugasundaram, Kulesh (). .
Wikimedia Commons has media related to .
, Stanford University Computer Science Library
, Stanford University Computer Science Library
(note that this technique was widely used for many decades before the patent was granted)
: Hidden categories:

我要回帖

更多关于 linking verb 的文章

 

随机推荐