[Introduction to Data Structures] Chapter 2: Linear Tables

Table of contents

1. The basic concept of linear table

(1) Basic concepts of linear tables 

(2) The logical structure characteristics of the linear table 

(3) Basic operations of linear tables

2. Sequential storage of linear tables 

(1) Type definition of linear table sequential storage 

(2) Realization of the basic operations of the linear table on the sequential table

(3) Analysis of the sequence table implementation algorithm

① insert

② delete

③ Positioning (search)

3. Link storage of linear tables 

(1) Type definition of singly linked list 

① Single linked list

② General graphic method of singly linked list

③ Type definition of singly linked list

④ Simple operation of single linked list

(2) Implementation of the basic operations of the linear table on the singly linked list 

① Initialization

② Find the length of the table

③ Table reading element

④ Positioning

⑤ insert

⑥ delete

4. Implementation of other operations on the singly linked list 

(1) Create a table 

(2) Delete duplicate nodes 

① Clear the duplicate node whose value is x in the singly linked list 

② Clear all duplicate nodes in the singly linked list 

5. Other linked lists 

(1) Circular linked list 

(2) Two-way circular linked list 

① Two-way circular linked list 

② Structure definition of doubly linked list

③ Insertion of nodes in the doubly linked list

④ Deletion of nodes in the doubly linked list

6. Comparison between sequence implementation and connection implementation 

(1) Advantages and disadvantages of linear list and linked list 

(2) Comparison of time performance




1. The basic concept of linear table

(1) Basic concepts of linear tables 

[Concept] A linear table is a finite sequence composed of n (n≥0) data elements (nodes) a1, a2, ..., an.

[Notation] The number n of data elements is defined as the length of the table:

① When n=0, it is called an empty table, which is recorded as: () or (direct space)
② Non-empty linear table (n>0), recorded as: L=(a1, a2,..., an)
  • a1 is called the starting node and an is the terminal node.
  • For any pair of adjacent nodes ai and ai+1 ( 1≤i<n ), ai is called the direct predecessor of ai+1, and ai+1 is called the direct successor of ai.
③ The data element ai (1≤i≤n) is just an abstract symbol, and its specific meaning can be different in different situations.

【Basic terms】

  • start node, end node, immediate predecessor, immediate successor, length of linear list, empty list
  • L=(a1,a2,…,an)
【Notice】
  • There is only one start node and one end node in the linear list
  • The starting node has no direct predecessor and has a direct successor
  • A terminal node has an immediate predecessor and no immediate successor
  • Except for these two nodes, each node has and only one immediate predecessor and one immediate successor

(2) The logical structure characteristics of the linear table 

For a non-empty linear list: the nodes in the linear list have a one-to- one relationship

  1. There is one and only one starting node a 1 , no direct predecessor, and one and only one direct successor  a 2
  2. There is one and only one terminal node a n , no direct successor, and one and only one direct predecessor  a n-1
  3. The remaining internal nodes a i (2≤i≤n-1) have  and only have one direct predecessor a i-1  and one direct successor  a i+1

(3) Basic operations of linear tables

Basic Operations of Linear Tables
initialization Initiate(L) Create an empty table L=(), L contains no data elements.
Find table length Length(L) Returns the length of the linear list L.
fetch cell Get(L,i) Return the i-th data element of the linear table, and return a special value when i does not satisfy 1≤i≤Length(L).
position Locate(L,x) Find the serial number of the node whose data element value is equal to x in the linear table. If there are multiple data element values ​​equal to x, the operation result is the minimum value of the serial numbers among these nodes. If the node cannot be found, the operation result is 0 .
insert Insert(L,x,i) Insert a new data element with the value x before the i-th data element of the linear table L, and the legal value range of the parameter i is 1≤i≤n+1.
After the operation, the linear table L changes from (a1, a2, ..., ai-1, ai, ai+1, ..., an) to (a1, a2, ..., ai-1, x, ai, ai+1, ..., an), add 1 to the length of the table.
delete Delete(L,i) Delete the ith data element ai of the linear table L, the valid value range of i is 1≤i≤n.
After deletion, the linear table L changes from (a1, a2, ..., ai-1, ai, ai+1, ..., an) to (a1, a2, ..., ai-1, ai+1, ..., an) , the length of the table is reduced by 1.


2. Sequential storage of linear tables 

(1) Type definition of linear table sequential storage 

  • The sequential storage method of the linear table is: the nodes in the table are stored in a group of continuous storage units in the computer memory in sequence, and the adjacency relationship of the data elements in the linear table determines their storage location in the storage space, that is, the logical structure The storage locations of adjacent nodes are also adjacent.
  • A linear table implemented with sequential storage is called a sequential table.
  • Arrays are generally used to represent sequential tables.

[Example] Sequential storage structure of linear table

  • Suppose there is a set of data, and there is an order among the data:
  • The order of the data here means the logical relationship between the data, that is, the linear relationship. This set of data is a linear table:
  • Assuming that the address of a1 is known as Loc(a1), and each data occupies c units, the ai address is calculated:
    Loc(ai) = Loc(a1) + c*(i-1)

  • The order of the data here means the logical relationship between the data, that is, the linear relationship. This set of data is a linear table:
  • When storing linear tables sequentially, you need to store: storage unit size, number of data
  • Linear table size: 10        MaxSize
    Linear table length: 7          Length
    The type of stored data:    DataType

[Example] Structure definition of sequence table

【Example code】

//定义常量Maxsize并初始化为100
const int Maxsize = 100;

//定义结构体Seqlist,包含一个数组和一个int类型的长度
typedef struct
{ 
   DataType data[Maxsize]; //数组,用于存储数据
   int length;             //当前数组中数据的个数
} Seqlist;

Seqlist L; //定义一个Seqlist类型的变量L

【Code Explanation】

  • The code defines a structure Seqlist, which contains an array data and length of int type, used to store data and the number of data in the current array.
  • At the same time, a constant Maxsize is defined, and a typedef is used to give Seqlist an alias for future use.
  • Finally, a variable L of type Seqlist is defined.
  1. const int Maxsize = 7;
    1. Use the const keyword to define an integer constant Maxsize, indicating that the maximum length of the array storing data in the sequence table is 7
  2. typedef struct
    1. Use the struct keyword to define a structure type named DataType
  3. {
    1. Braces at the start of a structure definition
  4. int whether;
    1. A member variable in the structure, representing the student ID of the student
  5. char name[8];
    1. The member variable in the structure represents the name of the student, and the length of the name is 8 characters
  6. char sex[2];
    1. The member variable in the structure indicates the gender of the student, and the length of gender is 2 characters
  7. int age;
    1. A member variable in the structure, representing the age of the student
  8. int score;
    1. The member variable in the structure indicates the student's entrance score
  9. } DataType;
    1. The curly braces at the end of the structure definition, followed by the definition of the alias DataType, which represents the alias of the structure type DataType
  10. typedef struct
    1. Use the struct keyword to define a structure type named seqList
  11. {
    1. Braces at the start of a structure definition
  12. DataType data[Maxsize];
    1. The member variable in the structure represents the array storing the data, the maximum length is Maxsize
  13. int length;
    1. The member variable in the structure indicates the number of data in the current array, that is, the actual length of the linear table
  14. } seqList;
    1. The curly braces at the end of the structure definition, followed by the definition of the alias seqList, which represents the alias of the structure type seqList
  15. seqList student;
    1. Define a sequence table variable student, which is a structure variable of seqList type, which contains an array data and a length member variable, which can be used to store the information of multiple students, that is, student number, name, gender, age and grade, etc. information.

【Illustration】

【in conclusion】

  • The sequence table is a linear table implemented with a one-dimensional array, and the array subscript can be regarded as the relative address of the element
  • Logically adjacent elements are stored in cells that are also physically adjacent
[Features] Features of sequential storage structure:
  • The logical structure of the linear table is consistent with the storage structure
  • Can implement random reads on data elements

【Illustration】 

【expression】

  • Assuming that all nodes in the linear table are of the same type, the storage space occupied by each node is also the same.
  • Assume that each node in the table occupies L storage units, and the storage address of the first unit is the storage address of the node.
  • And suppose the storage address of the starting node a1 in the table is d, then the storage address LOC(ai) of the node ai:
    LOC(ai)=d+(i-1)*L

(2) Realization of the basic operations of the linear table on the sequential table

Implementation of basic operations on sequence tables:

  • insert
  • delete
  • position

 

Advantages of sequential tables:
  • There is no need to add additional storage space to represent the logical relationship between nodes
  • Any node in the table can be easily accessed randomly
Disadvantages of sequential tables:
  • Insertion and deletion operations are inconvenient, and a large number of nodes must be moved
  • The sequence table requires continuous space, and storage allocation can only be done in advance, so when the table length changes greatly, it is difficult to determine the appropriate storage size

Insertion and deletion analysis conclusion: 

  • The linear table represented by the sequential storage structure needs to move about half of the data elements on average when inserting or deleting.
  • When the number of data elements in the linear table is large, and it is often inserted or deleted, this point needs to be considered. 【illustrate】
  • According to the above definition, the name of the sequence table is student, the maximum length of the table is 7, and the actual length value of the table is in student.length

(3) Analysis of the sequence table implementation algorithm

① insert

  • The insertion operation of a linear table refers to inserting a new node x at the i-th (1≤i≤n+1) position of the table to make a linear table with a length of n:
    (a1,…,ai-1,ai,…an)
  • becomes a linear list of length n+1:
    (a1,…,ai-1,x,ai,…an)
    ① When the table space is full, no more insert operations can be performed
    ② When the insertion position is an illegal position, the normal insertion operation cannot be performed

Sequence table insert operation process:

  • Move the nodes at positions n, n-1, ..., i in the table to positions n+1, n, ..., i+1 in turn, and leave the i-th position
  • Insert a new node x at this position. Only when the insertion position i=n+1, do not need to move the node, directly insert x into the end of the list
  • The sequence table length plus 1
  • The following figure is a schematic diagram of inserting a new node x=66 at position 3:

【Schematic Diagram】

 

[Example]  Insert a data element at L the first position of :ix

  • Before inserting, it is necessary to judge whether the table is full and whether the insertion position is legal
  • After the insertion is completed, the following elements need to be moved backwards by one position, thereby adding a new data element to the sequence table

[Specific algorithm description]

//在顺序表L的第i个位置插入元素x
void InsertSeqlist(SeqList L, DataType x, int i)
{   //将元素x插入到顺序表L的第i个数据元素之前
    //检查表是否已经满
    if (L.length == Maxsize) 
        exit("表已满");
    
    //检查插入位置i是否合法
    if (i < 1 || i > L.length+1)
        exit("位置错");
    
    //将i后面的每个元素都向后移一个位置
    for (j = L.length; j >= i; j--)   //初始i=L.length
        L.data[j] = L.data[j - 1];    //依次后移
    
    //将x插入到下标为i-1的位置
    L.data[i - 1] = x;
    
    //表长度加1
    L.length++;
}

【Code Explanation】

  • The function of this function is to insert element x in the ith position of the sequence list L.
  • In the function, first check whether the table is full, and if it is full, the program will be terminated.
  • Second, check whether the insertion position i is legal, if i is not within the range of 1~L.length + 1, then terminate the program.
  • Next, each element following i is shifted back one position to make room for the new element x.
  • Finally, insert x into the position whose subscript is i-1, and add 1 to the length of the table.
  1. void InsertSeqlist(SeqList L, DataType x, int i)

    • Function name:InsertSeqlist
    • Return value type: no return value, the function of this function is to directly modify the sequence table L
    • Parameter Type:
      • SeqList L: sequence table variable
      • DataType x: the value of the data element to insert
      • int i: The position of the data element to be inserted in the sequence table
  2. if (L.length == Maxsize)

    • Check if table is full
    • If the sequence table  L is full, it means that no new elements can be inserted. At this time, the program will use  exit() the system function to end the operation and output  "表已满" an error message
  3. if (i < 1 || i > L.length+1)

    • Determine whether the position of inserting data elements is legal
    • If  i the value of the internal parameter is less than 1 or greater  L.length+1, it means that the insertion position is illegal. At this time, the program will use  exit() the system function to end the operation and output  "位置错" an error message
  4. for (j = L.length; j >= i; j--)

    • Starting with the last data element, move  i each element after the position of the th element back one position to make room for the insertion of a new data element
    • j Start looping from  L the last element of the sequence table until position  i - 1,  a total L.length - (i-1) of elements need to be moved
  5. L.data[j] = L.data[j - 1];

    • j-1 Move the value of the th element  in the sequence table  to the right by one position, that is, assign the value to the j th element in the sequence table
  6. L.data[i - 1] = x;

    • Insert the functional element to be inserted  x into the position  i-1 , and complete the insertion operation in the sequence table
  7. L.length++;

    • Since a data element is inserted in the sequence table, the number of elements in the sequence table needs to be  L.length increased by one to update the number of data elements

Analysis of insertion algorithm: 

  • Assuming that there are n data elements in the linear table, there are n+1  positions that can be inserted when inserting 
  • The probability of inserting data at each position is: 1/(n+1)
  • When inserting at position i, move n-i+1  data
  • Assuming that the possibility of inserting elements at n+1 positions is equal, the average number of moving elements is:
  • Average time complexity O(n):

② delete

  • The deletion operation of a linear table refers to deleting the i-th node of the table to make a linear table with a length of n:
    (a1,…,ai-1,ai,ai+1,…,an)
  • Become a linear list of length n-1:
    (a1,…,ai-1,ai+1,…,an)
  • When the position i of the element to be deleted is not within the range of the table length (that is, i<1 or i>L->length), it is an illegal position, and normal deletion operations cannot be performed

 Sequence table delete operation process:

  1. If i=n, ​​just delete the terminal node without moving the node
  2. If 1≤i≤n-1, the nodes at positions i+1, i+2,...,n in the table must be moved forward to positions i, i+1,...,n-1 in order to fill Gaps caused by delete operations
  3. The length of the table is reduced by 1
  • Only when the position i=n is deleted, there is no need to move the node, and the length of the table can be directly set to -1
【Schematic Diagram】

[Example]L  Delete i the data element at the th positionin the sequence table 

  • First, you need to judge whether the position is legal (note, here is counting from 1)
  • If the position is legal, move the element behind the position to the left by one position, thereby deleting the data element at the position, and reducing the length of the sequence table by one
  • If the position is illegal, the program will be terminated directly and an error message will be output

[Specific algorithm description]

//删除线性表L中的第i个数据结点
void DeleteSeqList(SeqList L, int i) 
{
    //检查位置是否合法
    if (i < 1 || i > L.length)
        exit("非法位置");
     
    //将i后面的每个元素向左移动一个位置
    for (j = i; j < L.length; j++)   //第i个元素的下标为i-1
        L.data[j - 1] = L.data[j];   //依次左移
    
    //表长度减1
    L.length--;
}

【Code Explanation】

  • The function of this function is to delete the i-th data node in the linear table L.
  • The function first checks whether the location is legal, and if the location is not legal, the program is terminated.
  • Shifts each element following i one position to the left to make room for the deleted element x.
  • Finally, the element is deleted, and the length of the table is reduced by 1.
  1. void DeleteSeqList(SeqList L, int i)

    • Function name:DeleteSeqList
    • Return value type: no return value, the function of this function is to directly modify the sequence table L
    • Parameter Type:
      • SeqList L: sequence table variable
      • int i: The position of the element to be deleted in the sequence list
  2. if (i < 1 || i > L.length)

    • Determine whether the position of the element to be deleted is legal
    • If the position  i is less than 1 or  i greater than the length of the sequence table  L.length, it means that the position to be deleted is illegal. At this time, the program will use  exit() the system function to end the operation and output  "非法位置" an error message
  3. for (j = i; j < L.length; j++)

    • Starting from the position of the element to be deleted  i , move each element behind it to the left by one position, so that the deleted  i sequence table still maintains a continuous storage structure
    • j From  i the beginning of the loop to  L the last element of the sequence list,  a total L.length - i of elements need to be moved
  4. L.data[j - 1] = L.data[j];

    • j Move the value of the first element  in the sequence table  to the left by one position, that is, assign the value to the first j-1 element in the sequence table
  5. L.length--;

    • Since a data element is deleted from the sequence table, the number of elements in the sequence table needs to be  L.length reduced by one to update the number of data elements

Analysis of the deletion algorithm: 

  • Assuming that there are n data elements in the linear table, there are n  positions to delete when performing the delete operation
  • The probability of deleting data at each location is: 1/n
  • When deleting at position i, move ni data
  • Assuming that the possibility of deleting elements at n positions is equal, the average number of moving elements is:
  • When performing a deletion operation, assuming that the possibility of deleting each element is equal, the average number of moving elements is:
  • Average time complexity O(n):

③ Positioning (search)

The function of the positioning operation  LocateSeqlist(L,X)  is to seek the minimum value of the node sequence number in L whose value is equal to X, and the result is 0 when there is no such node.
[Example] L  Find the element whose value is in  the sequence table  x  and return its position in the sequence table:
  • First set the search start position to 0
  • Then loop through the ordered list to find  x an element with value
  • Returns its position if found, 0 if not found
【Schematic Diagram】

[Description of the specific algorithm] Start from the first element a1 and compare it with x sequentially until a data element equal to x is found, then return its storage subscript or serial number in the sequence table; or search the entire table and find no match Equal elements of x, return 0:

//在顺序表L中查找值为x的元素
int LocateSeqlist(SeqList L, DataType x)
{
    int i = 0;
    //在顺序表中查找值为x的结点
    while ((i < L.length) && (L.data[i] != x))
        i++;
    
    //若找到值为x的元素,返回元素的序号
    if (i < L.length)
        return i + 1;
    //未查找到值为x的元素,返回0
    else 
        return 0;
}

【Code Explanation】

  • The purpose of this function is to find the element with value x in the ordered list L.
  • In the function, the element with the value x is searched in the sequence table L through the while loop, and if the element with the value x is found, the sequence number of the element is returned.
  • Returns 0 if no element with value x is found.
  • To calculate the table length of the sequence table, just output  L.length directly  .
  1. int LocateSeqlist(SeqList L, DataType x)

    • Function name:LocateSeqlist
    • Return value type: int, the return value indicates the position of the found element in the sequence table
    • Parameter Type:
      • SeqList L: sequence table variable
      • DataType x: the element value to look up
  2. int i = 0;

    • Define an integer variable  ithat represents the position of the search in the current sequence table
  3. while ((i < L.length) && (L.data[i] != x))

    • Loop to find out whether the sequence table contains  x an element whose element value is
      • When  it is less than the length of the sequence table, and  the value of the element corresponding  to  i the current position  is not, continue to search, that is, find the first  element with a value in the sequence tableixx
  4. i++;

    • Constantly add 1 to the current search position, and continue to search backwards until  x an element with a value of 1 is found
  5. if (i < L.length)

    • If the current search position  i is less than the length of the sequence table
  6. return i + 1;

    • Returns the position of the element whose value is found  x in the sequence table, counting from 1
  7. else

    • x If no element is found in the ordered list with value 
  8. return 0;

    • x Returns 0, indicating that no element with value was found 
When analyzing the sequential table implementation algorithm of a linear table, an important indicator is the number of comparisons and moves of data elements.
1. Let the length of the table be length=n. In the insertion algorithm, the number of movement of elements is not only related to the length n of the sequence table, but also related to the inserted position i.
  • The insertion algorithm has a time complexity of O(n) in the worst case  .
  • In general, the number of element comparisons and moves is  n-i+1  times, and the average number of moves of the insertion algorithm is about  n/2 , and its time complexity is O(n) .
2. Delete the algorithm DeleteSeqlist, you can get:
  • In the worst case, the number of element moves is  n-1 , and the time complexity is O(n) . The average number of element moves is about (n-1) /2 , and the time complexity is  O(n) .
3. For the positioning algorithm, elements in the sequence table need to be scanned.
  • The standard operation is to compare the parameter x with the node value in the table, and the average time complexity is O(n) . 
  • The time complexity of the algorithm  for finding the length of the table and reading the elements of the table is O(1) , which has reached the lowest level in terms of order.


3. Link storage of linear tables 

The linear list stored in the link mode is called a linked list for short:
  • Link List
The specific storage of the linked list is expressed as:
  • Use an arbitrary set of memory cells to store
  • The logical order and physical order of the nodes in the linked list are not necessarily the same. must also store address information indicating its successor node

 


(1) Type definition of singly linked list 

① Single linked list

【Schematic Diagram】 

【illustrate】

  • data field: the data field that stores the node value
  • next field: the pointer field (chain field) that stores the address (location) of the direct successor of the node
  • All nodes are linked by pointers to form a singly linked list
  • NULL is called: null pointer
  • Head is called: head pointer variable, which stores the address of the first node in the linked list

② General graphic method of singly linked list

【illustrate】 

  • Since we often only pay attention to the logical order between nodes and do not care about the actual position of each node, we can use arrows to represent the pointers in the chain domain, and the singly linked list can be expressed as the following figure
  • The function of adding a head node: generally no data is stored in the first node in the singly linked list, which is called the head node , and the head pointer is used to store the address of the node

【Schematic Diagram】

③ Type definition of singly linked list

[Example] A structure type of linked list node is defined node, which contains data field data and pointer field  and nextare defined at the same time to facilitate the writing of subsequent programs.NodeLinkList

【Schematic Diagram】

[Specific algorithm description] 

//定义链表节点结构体
typedef struct node
{ 
    DataType data; //数据域
    struct node* next; //指向下一个节点的指针域
} Node, *LinkList;

【Code Explanation】 

  • This code defines a node structure of a linked list.
  • Each node contains a data field data, which stores the data of the node, and a pointer field next pointing to the next node.
  • At the same time, the typedef keyword is used to define two new types, one is Node, which represents the node type, and the other is LinkList, which represents the linked list type.
  • LinkList type is a pointer to Node type.
  • This linked list is a one-way linked list, each node contains only a pointer to the next node.
  1. typedef struct node

    • struct Define a struct type  using  keywordsnode
  2. {

    • Braces at the start of a structure definition
  3. DataType data;

    • The member variables in the structure represent the data field of the node
  4. struct node* next;

    • The member variable in the structure represents the pointer field of the node, pointing to the next node
  5. } Node, *LinkList;

    • The braces at the end of the structure definition are followed by two aliases, which represent  the alias of Node the structure type  and  the alias of the pointer  to the structure type  . Therefore, using   the declared pointer is a pointer to the head node of the linked list.nodeLinkListnodeLinkList

④ Simple operation of single linked list

Singly linked list features:
  • The starting node is also called the first node and has no predecessor, so the head pointer head is set to point to the starting node.
  • The linked list is uniquely determined by the head pointer, and the singly linked list can be named by the name of the head pointer. A linked list whose head pointer name is head can be called a list head.
  • The terminal node is also called the tail node and has no successor, so the pointer field of the terminal node is empty, that is, NULL
  • Nodes other than the head node are table nodes
  • For the convenience of operation, no data is stored in the head node

【Schematic Diagram】

【illustrate】 

  • head is the head pointer of the linked list, so it is a pointer type variable.
  • head stores the address of the head node.
  • The first element node: head->next

(2) Implementation of the basic operations of the linear table on the singly linked list 

① Initialization

[Example] Initialize an empty singly linked list

  • By dynamically allocating memory space, create a  Node head node with a size of , set the next node pointer field of the head node to a null pointer, and finally return the pointer of the head node, indicating that there is no data in the singly linked list
  1. Create an empty singly linked list L, InitiateLinkList(L)
  2. An empty singly linked list is composed of a head pointer and a head node
  3. Assuming that the pointer variable t has been defined, let t point to a head node
  4. And let the next of the head node be NULL

【Notice】

  • When the head node is generated, a new node is generated by the malloc function

[Special attention] The usage format and function of malloc function

  • [Format] The format of the dynamic memory allocation function malloc function is as follows:
    (数据类型*)malloc(sizeof(数据类型))
    // 示例:
    int *p;p=(int *)malloc(sizeof(int))

[Description of the specific algorithm] The empty list consists of a head pointer and a head node. The algorithm is described as follows:

//初始化一个空的单链表
LinkList InitiateLinkList()
{
    LinkList head; //头指针
    head = malloc(sizeof(Node)); //动态构建一个节点,它是头节点
    head->next = NULL; //头节点的指针域为空
    return head;
}

【Code Explanation】

  • The function of this function is to initialize an empty singly linked list.
  • The function first defines a head pointer head.
  • Then use the malloc function to dynamically allocate a head node, and point the pointer field of the head node to NULL.
  • Finally, return the head pointer head.
  • In the algorithm, the variable head is the head pointer of the linked list, which points to the newly created node, the head node.
  • An empty singly linked list has only one head node, and its pointer field is NULL.
  1. LinkList InitiateLinkList()

    • Function name:InitiateLinkList
    • Return value type: LinkList, which returns a pointer to the head node of the linked list
    • Parameter type: no parameter
  2. LinkList head;

    • Declare a  Node pointer to type  headthat represents the head node of the linked list
  3. head = malloc(sizeof(Node));

    • Use  malloc dynamic allocation of a  Node memory space of size and return the address of the space to the pointer head
  4. head->next = NULL;

    • Set the pointer field of the head node of the linked list to a null pointer, because there is no node in the linked list except the head node at this time
  5. return head;

    • Returns a pointer to the head node  head, thereby initializing an empty singly linked list

② Find the length of the table

【Schematic Diagram】

【illustrate】 

  • In the single linked list storage structure, the length of the linear list is equal to the number of nodes contained in the single linked list ( excluding the head node )

【Schematic Diagram】

【step】 

  • Let counter j be 0
  • Let p point to the head node
  • When the next node is not empty, j is incremented by 1, and p points to the next node
  • The value of j is the number of nodes in the linked list, that is, the length of the list

[Example] Get head the length of

  • Define a pointer  pto point to the head node of the linked list, obtain the length of the linked list by traversing the linked list, and finally use the length of the linked list as the return value of the function

【Notice】

  • The role of p=p->next 

[Description of the specific algorithm] The empty list consists of a head pointer and a head node. The algorithm is described as follows:

//获取单链表的长度
int lengthLinklist(LinkList head)
{ 
    Node* p; //定义一个指针p,用于遍历链表
    p = head; //指向链表头节点
    int j = 0; //用于记录链表长度的计数器
    while (p->next != NULL) //当指针p没有指向链表尾节点时
    { 
        p = p->next; //指针p指向下一个节点
        j++; //链表长度加1
    }
    return j; //返回链表长度
}

【Code Explanation】

  • The function of this function is to get the length of the singly linked list.
  • A pointer p is defined in the function for traversing the linked list.
  • The pointer p starts from the head node of the linked list and loops through the linked list until the tail node of the linked list.
  • During the traversal, the counter j is used to record the length of the linked list.
  • Finally, return the value of the counter j, which is the length of the linked list.
  1. int lengthLinklist(LinkList head)

    • Function name:lengthLinklist
    • Return value type: int, which returns the length of the linked list
    • Parameter Type:
      • LinkList head: Pointer to the head node of the linked list (the head node of the linked list does not contain data, and the next node is the first node of the linked list)
  2. Node* p;

    • Declares  Node a pointer to type  pfor traversing the linked list
  3. p = head;

    • Point the pointer  p to the head node of the linked list and start traversing from the head of the linked list
  4. int j = 0;

    • Declare an integer variable  j, used to record the counter of the length of the linked list
  5. while (p->next != NULL)

    • When the pointer  p does not point to the tail node of the linked list (that is,  p the next node is not empty)
  6. p = p->next;

    • Point the pointer  p to the next node, that is,  p point to the next node in the linked list
  7. j++;

    • The length counter of the linked list  j is increased by 1, indicating that a node has been traversed currently
  8. return j;

    • After the traversal, return the length of the linked list, that is,  j the value of the counter

③ Table reading element

【Schematic Diagram】

[Step] Find the i-th node

  • Let counter j be 0
  • Let p point to the head node
  • When the next node is not empty and j<i, j is incremented by 1, and p points to the next node
  • If j is equal to i, then the node pointed to by p is the i-th node to be found; otherwise, there is no i-th node in the linked list

[Example] Find the first node in the linked list i and return the pointer of the node, if not found, return a null pointer

[Specific algorithm description]

// 获取链表中第 i 个节点的指针
Node* GetlinkList(LinkList head, int i) {
    Node* p;
    p = head->next; // 将 p 指向链表的第一个节点
    int c = 1; // 用 c 记录当前节点位置
    while ((c < i) && (p != NULL)) // 当前节点位置小于 i 且 p 不为空时
    {
        p = p->next; // 将 p 指向下一个节点
        c++; // 位置加一
    }
    if (i == c) // 如果当前节点位置等于 i,则返回当前节点的指针
        return p;
    else
        return NULL; // 否则返回空指针
}

【Code Explanation】

  1. Node* GetlinkList(LinkList head, int i)

    • Function name:GetlinkList
    • Return value type: Node*, which is  Node a pointer to type
    • Parameter Type:
      • LinkList head: Pointer to the head node of the linked list (the head node of the linked list does not contain data, and the next node is the first node of the linked list)
      • int i: The position of the node to be found in the linked list
  2. Node* p;

    • declares a  Node pointer to type p
  3. p = head->next;

    • Point the pointer  p to the next node of the linked list  head , which is the first node in the linked list
  4. int c = 1;

    • Define a variable  cto record the position of the currently processed node in the linked list, initialized to 1, that is, the position of the first node
  5. while ((c < i) && (p != NULL))

    • Enter a While loop
    • The loop condition is: the position of the currently processed node in the linked list is less than the position to be searched  i and the current pointer  p is not empty
    • When the loop ends, p it will point to the target node or be empty
  6. p = p->next;

    • In the loop, point the pointer  p to the next node each time
  7. c++;

    • In the loop,  c add 1 to the variable each time, indicating that  p the position of the node pointed by the current pointer in the linked list is increased by 1
  8. if (i == c)

    • Determine whether the position of the current node in the linked list is equal to the position to be found i
  9. return p;

    • If the position of the current node in the linked list is equal to the position to be searched  i, then directly return the pointer of the node p
  10. else

    • If the condition is not met, a null pointer is returned  NULL, indicating that the target node was not found

④ Positioning

  • The positioning operation is to find the position of the element given the value of the table element.
  • For a singly linked list, given the value of a node, find out which node this node is in the singly linked list.
  • Positioning operations are also known as lookup by value.
Specific steps:
  1. Let p point to the head node
  2. order i=0
  3. When the next node is not empty, p points to the next node, and the value of i increases by 1
  4. Until the value of the node pointed to by p is x, return the value of i+1
  5. If no node value x is found, the return value is 0

【illustrate】

  • The positioning operation of the linear table is to find out the position of the element given the value of the table element.
  • In the implementation of the singly linked list, given the value of a node, find out which node this node is in the singly linked list.
  • Positioning operations are also known as lookup by value.
  • In the positioning operation, it is also necessary to visit the linked list from the beginning to the end until the required node is found and its serial number is returned.
  • Returns 0 if not found.

[Example]head  Find x the first node whosein the linked list 

[Specific algorithm description]

// 在链表中查找第一个与 x 相等的节点,返回节点的序号
// 如果不存在这样的节点,则返回 0
int LocateLinklist(LinkList head, DataType x)
{
    Node *p = head; // 将工作指针 p 指向链表头结点
    p = p->next; // 将工作指针 p 指向链表的第一个节点
    int i = 0; // 初始化结点序号为 0
    while (p != NULL && p->data != x) // 当 p 非空且 p 所指向节点的数据域不为 x 时
    {
        i++; // 结点序号加一
        p = p->next; // 工作指针指向下一个节点
    }
    if (p != NULL) // 如果 p 不为空,说明找到了相应的节点
        return i + 1; // 返回节点的序号
    else
        return 0; // 否则返回 0
}

【Code Explanation】 

  1. int LocateLinklist(LinkList head, DataType x)

    • Function name:LocateLinklist
    • Return value type: int, indicating the serial number of the node, if no corresponding node is found, return 0
    • Parameter Type:
      • LinkList head: Pointer to the head node of the linked list (the head node of the linked list does not contain data, and the next node is the first node of the linked list)
      • DataType x: the value of the node to look up
  2. Node *p = head;

    • Declare a  Node pointer to type  pand point it to the linked list head
  3. p = p->next;

    • Point the pointer  p to the first node of the linked list
  4. int i = 0;

    • Initialize the node number to 0
  5. while (p != NULL && p->data != x)

    • Enter a While loop
    • The loop condition is: the value of the currently processed node is not equal to the value to be found  x, and the current pointer  p is not empty
    • When the loop ends, p it will point to the target node or be empty
  6. i++;

    • In the loop, add 1 to the node number each time, indicating that a node has been processed
  7. p = p->next;

    • In the loop, point the pointer  p to the next node each time
  8. if (p != NULL)

    • Determine whether the current node is empty
  9. return i + 1;

    • If the current node is not empty, return the sequence number of the current node plus 1
  10. else

    • Returns 0 if the current node is empty

⑤ insert

The insertion operation is to insert a new node whose value is x into the position of the ith node in the table, that is, between ai-1 and ai.
Specific steps:
  1. Find ai-1 storage location p
  2. Generate a new node *s with data field x
  3. Let the pointer field of node *p point to the new node
  4. The pointer field of the new node points to the node ai

[Example] Insert a  new node whose value is before the first data element node head in the linked list If the insertion position does not exist, output an error message and exit, otherwise insert a new node at the positionix

【Schematic Diagram】

[Specific algorithm description]

// 在链表 head 的第 i 个数据元素结点之前插入一个以 x 为值的新结点
void InsertLinklist(LinkList head, DataType x, int i)
{
    Node *p, *q;
    if (i == 1)
        q = head;
    else
        q = GetLinklist(head, i - 1); // 找到第 i-1 个数据元素结点
    if (q == NULL) // 第 i-1 个结点不存在
        exit("找不到插入的位置");
    else
    {
        p = malloc(sizeof(Node)); // 生成新结点
        p->data = x; // 新结点的数据赋值为 x
        p->next = q->next; // 新结点的链域指向*q的后继结点
        q->next = p; // 修改*q的链域
    }
}

【Code Explanation】

  1. void InsertLinklist(LinkList head, DataType x, int i)

    • Function name:InsertLinklist
    • Return value type: void, which does not return any value
    • Parameter Type:
      • LinkList head: Pointer to the head node of the linked list (the head node of the linked list does not contain data, and the next node is the first node of the linked list)
      • DataType x: the value of the node to insert
      • int i: The position to be inserted, that is,  i to insert a new node before the first data element node
  2. Node *p, *q;

    • Declares  Node a pointer to type, p pointing to a new node, q pointing to the th  i-1 data element node
  3. if (i == 1)

    • If i is equal to 1, the new node will be inserted after the head node
  4. q = head;

    • If i is equal to 1, it will directly  q point to the head node
  5. else

    • If i is greater than 1, you need to find the first  i - 1 data element node
  6. q = GetLinklist(head, i - 1);

    • Call  the function to return  the pointer of the first data element node  GetLinklist in the linked list i - 1q
  7. if (q == NULL)

    • If  q it is a null pointer, it means that the insertion position does not exist
  8. exit("找不到插入的位置");

    • Print an error message and exit the program
  9. else

    • If  q it is not a null pointer, it means that the insertion position exists
  10. p = malloc(sizeof(Node));

    • Dynamically allocate a  Node memory space of size and return the address of the space to the pointer p
  11. p->data = x;

    • Assign the data field of the new node to x
  12. p->next = q->next;

    • Point the chain field of the new node to the ith data element node, which is the successor  q node
  13. q->next = p;

    • Point the chain domain of the th  i-1 data element node to the new node, making it the new th  i data element node

[Note] The execution order of the link operations p->next=q->next and  q->next=p  cannot be reversed, otherwise the chain domain value of node *q (that is, the value pointing to the i -th node in the original table pointer) will be lost. 

⑥ delete

[Algorithm ideas] This algorithm describes deleting the i-th node
  1. Find the i-1th node; if it exists, continue, otherwise end;
  2. Delete the i-th node, and release the corresponding memory, end.

[Algorithm steps] The deletion operation is to delete the i-th node of the table

  1. Find the memory location p of ai-1
  2. Let p->next point to the direct successor node of ai
  3. Release the space of node ai and return it to the "storage pool" 

[Explanation] The basic operation to delete the i-th node in the singly linked listis:

  • Find the i-1th node in the linear list and modify its pointer to the successor

[Example] Delete  the first nodehead in i

  • If the node does not exist, output an error message and exit, otherwise remove the node from the linked list and release the memory space it occupies

【Schematic Diagram】

[Specific algorithm description]

// 删除表 head 的第 i 个结点
void DeleteLinklist(LinkList head, int i)
{
    Node *q, *p;
    if (i == 1)
        q = head;
    else
        q = GetLinklist(head, i - 1); // 先找待删结点的直接前驱
    if (q != NULL && q->next != NULL) // 若直接前驱存在且待删结点存在
    {
        p = q->next; // p 指向待删结点
        q->next = p->next; // 移出待删结点
        free(p); // 释放已移出结点 p 的空间
    }
    else
        exit("找不到要删除的结点"); // 结点不存在
}

【Code Explanation】

  1. void DeleteLinklist(LinkList head, int i)

    • Function name:DeleteLinklist
    • Return value type: void, which does not return any value
    • Parameter Type:
      • LinkList head: Pointer to the head node of the linked list (the head node of the linked list does not contain data, and the next node is the first node of the linked list)
      • int i: the position of the node to be deleted, that is, to delete the first  i node
  2. Node *q, *p;

    • Declare  Node pointers to types  q and  p, q pointing to the immediate predecessor of the node to be deleted, p pointing to the node to be deleted
  3. if (i == 1)

    • If i is equal to 1, the node to be deleted is the head node, so it will  q point to the head node
  4. q = head;

    • If i is equal to 1, it will  q point to the head node
  5. else

    • If i is greater than 1, you need to find the immediate predecessor of the node to be deleted
  6. q = GetLinklist(head, i - 1);

    • Call  the function to return  the pointer of the first data element node  GetLinklist in the linked list i - 1q
  7. if (q != NULL && q->next != NULL)

    • If the immediate predecessor node  q is not a null pointer and the node to be deleted exists
  8. p = q->next;

    • Point the pointer  p to the node to be deleted, that is,  q the successor node of
  9. q->next = p->next;

    • Point the next node of the pointer  q to the next node of the node to be deleted, that is, remove the node to be deleted from the linked list
  10. free(p);

    • p frees space for moved out nodes 
  11. else

    • if node does not exist
  12. exit("找不到要删除的结点");

    • Print an error message and exit the program

[Note] free(p) is essential, because when a node is removed from the linked list, if its space is not released, it will become a useless node, and it will always occupy the system memory space, other Programs will not be able to use this space.



4. Implementation of other operations on the singly linked list 

(1) Create a table 

This process is divided into three steps:

  1. First create an empty table with the head node
  2. Secondly, create a new node, and then link the new node to the head node, this node is the tail node (also the first node)
  3. Repeat the two steps of creating a new node and linking the new node to the end of the list until all elements in the linear list are linked to the singly linked list, here use int instead of DataType

[Method 1]  It is realized through the implemented insertion algorithm InsertLinklist (LinkList head, int x, int i) , and the insertion position i is increased sequentially, so that the new node is linked into the linked list.

[Example] The operation of creating a singly linked list

【Example code】

// 建立单链表
LinkList CreatLinklist()
// 通过调用InitiateLinklist和Insertlinklist实现建表算法。假定0是输入结束标志
{
    // 创建头结点
    LinkList head;
    int x, i;
    head = InitiateLinklist();      // 建立空表:初始化链表,创建头结点

    // 循环插入结点
    i = 1;                          // 置插入位置初值
    scanf("%d", &x);                // 读入第一个数据元素,x为整型
    while (x != 0)                  // 输入的不是结束标志时继续插入
    {
        InsertLinklist(head, x, i); // 将输入插入到head表尾:在链表的第i个位置插入值为x的结点
        i++;                        // 修改插入位置
        scanf("%d", &x);            // 读下一元素
    }

    return head;  // 返回创建好的单链表头结点指针
}

【Code Explanation】

  • Inside the function, first call  InitiateLinklist the function to create an empty linked list and create the head node  head.
  • Then read the data elements through a loop and insert them into the singly linked list until the end flag 0 is read.
  • When inserting each time, call  InsertLinklist the function to insert the data element into the head of the singly linked list, and  i add 1 to the insertion position to prepare for the insertion of the next data element.
  • Finally, return the head node pointer of the singly linked list  head.
  1. LinkList CreatLinklist()

    • Function name:CreatLinklist
    • Return value type: pointer to the head node of the singly linked list, the type is LinkList
    • Parameter type: no parameter
  2. LinkList head; int x, i;

    • Define  head, x and  i three variables, which respectively represent the head node pointer of the singly linked list, the input data element and the insertion position
  3. head = InitiateLinklist();

    • Call to  InitiateLinklist create an empty linked list, that is, initialize the linked list and create the head node, and assign the head node pointer to head
  4. i = 1;

    • Set the initial value of the insertion position to 1, indicating that the data element is inserted into the first position of the linked list
  5. scanf("%d", &x);

    • Read an integer data element from standard input and store it in a  x variable
  6. while (x != 0)

    • When the read data element is not 0, the loop performs the following operations:
  7. InsertLinklist(head, x, i);

    •  Insert a   new node with value at position head 1 in  the singly linked list ix
  8. i++;

    • Increment the insertion position by 1 to prepare for the insertion of the next data element
  9. scanf("%d", &x);

    • Reads the next integer data element from standard input, storing it in a  x variable
  10. return head;

    • Return the pointer to the head node of the created singly linked list head

[Method 2] The algorithm of method 1 starts to search from the head of the table every time it is inserted, which is a waste of time: because every time a new node is linked to the end of the table, we can use a pointer to point to the end node, so that Indicates the insertion position for the next new node

[Example 1] The operation of creating a singly linked list

【Schematic Diagram】

[Example code] The function name CreatLinklist2, the return value is the head node pointer of the singly linked list, and the type is LinkList:

// 建立单链表
LinkList CreatLinklist2()
//q是一个LinkList类型的变量,用来指示链入位置
{
    // 创建头结点
    LinkList head;
    Node *q, *t;
    int x;
    head = (Node *)malloc(sizeof(Node));      // 创建头结点

    q = head;                                 // 尾指针置初值,指向头结点
    scanf("%d", &x);                          // 读入第一个数据元素 x
    while (x != 0)                            // 输入的不是结束标志时继续插入
    {
        t = (Node *)malloc(sizeof(Node));     // 生成一个新结点
        t->data = x;                          // 给新节点赋值
        q->next = t;                          // 新节点t插入到链表中
        q = t;                                // 修改尾指针 q,指向新的尾结点
        scanf("%d", &x);                      // 读下一元素
    }

    q->next = NULL;       // q指向尾结点,置尾结点标志
    return head;          // 返回头结点指针
}

【Code Explanation】

  • This function code implements the operation of creating a singly linked list.
  • Inside the function, the head node of the singly linked list is created at the beginning  head.
  • In the loop, use  malloc the function to allocate memory space, create a new node for the new data element  t, and assign the input data element to  the members t of  the new node data .
  • Then, insert a new node  t at the end of the linked list, and point the tail pointer  q to the new tail node  t.
  • q When the end mark is encountered, the pointer of  the tail node  next is set to  NULL, indicating that the linked list has ended, and finally the head node pointer of the singly linked list is returned  head, indicating that the singly linked list has been created successfully.
  1. LinkList CreateLinklist2()

    • Function name:CreateLinklist2
    • Return value type: pointer to the head node of the singly linked list, the type is LinkList
    • Parameter type: no parameter
  2. LinkList head; Node *q, *t; int x;

    • Definition  head, q and  t three variables, which respectively represent the head node pointer, tail node pointer and newly created node pointer of the singly linked list; definition  x represents the input data element
  3. head = (Node *)malloc(sizeof(Node));

    • Use  malloc the function to allocate memory space, the allocated memory size is  Node the size of the structure, and assign the allocated memory address to the head node pointer head
  4. q = head;

    • Set the initial value of the tail pointer  q to the head node head
  5. scanf("%d", &x);

    • Read an integer data element from the standard input stream and store it in a  x variable
  6. while (x != 0)

    • As long as the input data element is not an end marker, do the following:
  7. t = (Node *)malloc(sizeof(Node));

    • Create a new node  tand use  malloc the function to allocate memory space
  8. t->data = x;

    • t Assigns a member of  the new node  data , setting it to the value of the input data element x
  9. q->next = t;

    • Insert a new node  t into the linked list, that is, put the new node  behind t the original tail node  q , and  q point to the new node t
  10. q = t;

    • Point the tail pointer  q to the new tail node t
  11. scanf("%d", &x);

    • Reads the next integer data element from the standard input stream and stores it in a  x variable
  12. q->next = NULL;

    • q The pointer of  the end node  next is set to  NULLindicate the end of the linked list
  13. return head;

    • Returns the head node pointer of the singly linked list  head, that is, the successfully created singly linked list

[Method 2] The algorithm of method 1 starts to search from the head of the table every time it is inserted, which is a waste of time: because every time a new node is linked to the end of the table, we can use a pointer to point to the end node, so that Indicates the insertion position for the next new node

[Example 2] The operation of creating a singly linked list

【Schematic Diagram】

【Example code】

// 建立单链表
LinkList CreatLinklist3()
{
    // 创建头结点
    LinkList head;                // 定义头结点
    Node *p;                      // 定义一个指向Node类型的指针,用于遍历链表
    int x;                        // 定义一个节点的数据
    head = malloc(sizeof(Node));  // 创建头结点,动态分配内存空间

    head->next = NULL;            // 头结点的next指针指向NULL
    scanf("%d", &x);              //读入节点的数据
    while (x)                     // x=0 时结束输入:如果节点数据不为0,就一直循环插入节点
    {
        p = malloc(sizeof(Node)); // 动态分配内存空间,创建新节点
        p->data = x;              // 给节点赋值
        p->next = head->next;     // 前插:插入到链表的第一个结点处
        head->next = p;           // 让头结点的next指针指向新插入的结点,从而将新节点加入到链表中
        scanf("%d", &x);          // 读入节点数据
    }

    return head; // 返回链表头结点
}

【Code Explanation】

  • This function is used to create a singly linked list. At the beginning of the function, a return value of LinkList type is declared, which means that this function returns the head node of the linked list. Each node contains a data and a pointer to the next node.
  • This function first creates the head node, and then continuously reads in new node data until the read data is 0.
  • When reading new node data, the program creates a new node and assigns it a value, and then adds it to the first position of the linked list.
  • The head insertion method is used here, that is, let the new node point to the original first node, and then let the head node point to the new node.
  • Finally return the head node.

 1.  Define the head node

LinkList head;    // 定义头结点
  • First, a head node of LinkList type is defined, and the LinkList type is defined as:
    typedef struct Node *LinkList;
  • The Node structure is defined as follows:
    struct Node {
      int data;        // 存储节点数据
      Node *next;      // 存储指向下一个节点的指针
    };

2.  Dynamically allocate memory space and create head nodes

  • Use the malloc function to allocate memory space to the head node
    head = malloc(sizeof(Node)); // 创建头结点,动态分配内存空间

3.  Head node initialization

  • Point the next pointer of the head node to NULL
    head->next = NULL; // 头结点的next指针指向NULL

4.  Read the data of the node, create the node and insert it into the linked list

  • First read the data of the node, if the node data is not 0, the node will be inserted in a loop. First, dynamically allocate memory space, create a new node, and assign a value to it. Then insert the newly created node into the first position of the original linked list, that is, let the next pointer of the new node point to the original first node, and then let the next pointer of the head node point to the new node. The forward interpolation method is used here, so every time a new node is inserted into the linked list, it is the original first position.
    scanf("%d", &x);  // 读入节点的数据
    while (x) {       // x=0 时结束输入, 如果节点数据不为0,就一直循环插入节点
      p = malloc(sizeof(Node)); // 动态分配内存空间,创建新节点
      p->data = x;              // 给节点赋值
      p->next = head->next;     // 前插:插入到链表的第一个结点处
      head->next = p;           // 让头结点的next指针指向新插入的结点,从而将新节点加入到链表中
      scanf("%d", &x);          // 读入节点数据
    }

5.  Return the head node of the linked list

  • Finally return the head node of the linked list
    return head;  // 返回链表头结点

【Notice】

  • In this code, the malloc function is used to dynamically allocate memory space, and the allocated memory needs to be released at the end
  • In C++, it is not recommended to use malloc to allocate memory, but to use the new operator, which can avoid some memory management problems.
  • In addition, it is recommended to add a statement to release node garbage memory in the code to prevent memory leaks.

(2) Delete duplicate nodes 

① Clear the duplicate node whose value is x in the singly linked list 

[Analysis] Clear the duplicate nodes with the value x in the singly linked list

【step】 

  1. Find the first node position with value x, p points to this node
  2. Start searching backward from the node pointed to by p, if there is a node with value x, let q point to the node before x to perform the delete operation, and continue to search until the end of the linked list

② Clear all duplicate nodes in the singly linked list 

【 Analysis of Stepwise Refinement

[ overall steps]

  1. When the end of the linked list is not reached (when ai is not a terminal node)
  2. Delete the node whose value is ai from ai+1 to an node
  3. i++
i=1
While(ai不是终端结点)
{ 删除 ai+1 到 an 结点中值为 ai 的结点
  i++
}

Further detailed analysis】

[ further refinement steps]  

  1. When the end of the linked list is not reached (when ai is not a terminal node)
  2. Delete the node whose value is ai from ai+1 to an node
  3. j=i
while (j<n)
{ if(aj==ai) 删除 aj
  j++
} 
i++

[Example] A function to delete redundant duplicate nodes in a singly linked list

  • The function receives the head node pointer of a linked list, deletes all redundant nodes, and ensures that the value of each node is unique

【Schematic Diagram】

【Example code】

// 删除表head中多余的重复结点
void PurgeLinklist(LinkList head)
{ 
    Node *p, *q, *r;  // 定义三个指向 Node 类型的指针,其中 p 为当前工作指针,q 为当前需要检查的指针,r 为需要删除的结点指针
    q = head->next;   // 初始化为当前第一个结点:q指示当前检查结点的位置,置其初值指向首结点
    while (q != NULL) // 当前检查结点*q不是尾结点时,寻找并删除它的重复结点:当当前检查指针 q 不为空时,继续循环
    {
        p = q;                  // 工作指针*p指向当前检查指针*q
        while (p->next != NULL) // 当工作指针*p的后继结点存在时:将其数据域与*q数据域比较
        { 
            if (p->next->data == q->data) // 若工作指针的下一个指针*(p->next)的数值等于当前检查指针*p的数值:若*(p->next)是*q的重复结点
            {
                r = p->next;              // 删除 r 指向待删节点
                p->next = r->next;        // 移出结点* (p->next),p->next指向原来* (p->next)的后继结点
                free(r);                  // 释放待删节点的内存空间
            }
            else 
            {
                p = p->next;              // 否则,让工作指针*p指向下一个结点,继续检查
            }
        }
        q = q->next; // 更新检查结点:更新当前检查指针*p
    }
}

【Code Explanation】

  • This code is a function for deleting redundant duplicate nodes in a singly linked list
  • The basic implementation idea is to cycle through the entire linked list based on each node in the singly linked list, compare each node with the data of all nodes behind it, and delete the node behind it when encountering a node with the same data
  • The function receives the head node pointer of a linked list, deletes all redundant nodes, and ensures that the value of each node is unique

  1.  Define three pointers to the Node type

  • Among them, p is the current working pointer, q is the current pointer to be checked, and r is the node pointer to be deleted
    Node *p, *q, *r; // 定义三个指向 Node 类型的指针,其中 p 为当前工作指针,q 为当前需要检查的指针,r 为需要删除的结点指针

2.  Initialize the check pointer

  • Set the pointer q that should be checked to the first common node currently to be checked
    q = head->next; // 初始化为当前第一个结点

3.  Outer loop

  • Enter the outer while loop, when the current check pointer q is not empty, continue to loop until the entire linked list is checked
    while (q != NULL) // 当当前检查指针 q 不为空时,继续循环

4.  Inner loop

  • Enter the inner while loop, when the successor node of the working pointer exists, compare its data field with the data field of the current pointer q to be checked. If  the successor node of p is the duplicate node of q, point r to the node to be deleted, move out the node  (p->next), and release the memory space of the node to be deleted. Otherwise, let p point to the next node
    while (p->next != NULL) // 当工作指针的后继结点存在时

5.  Update the pointer to be checked

  • Update the current pointer q that needs to be checked
    q = q->next; // 更新当前检查指针 q

6.  Physical release of memory space

  • After deleting redundant nodes, when the program no longer needs these memory spaces, these spaces need to be released in time to avoid memory leaks
    free(r); // 释放待删节点的内存空间

【Notice】

  • This function is recommended to be implemented using the containers and algorithms provided by the standard library


5. Other linked lists 

(1) Circular linked list 

【illustrate】 

  • The next value of the terminal node of the ordinary linked list is NULL
  • The next of the terminal node of the circular linked list points to the head node
  • In a circular linked list, the entire linked list can be scanned from any node

【Schematic Diagram】 

The way to find the tail node  of  ordinary linked list / circular linked list :

  • Attaching a rear  pointer to the tail node in the circular linked list  is suitable for linked list operations that often use head and tail nodes


(2) Two-way circular linked list 

① Two-way circular linked list 

[Description]  Set two pointer fields in the linked list:

  • a pointer to the successor node
  • A pointer to the predecessor node
  • Such a linked list is called a doubly linked list

【Schematic Diagram】 

 

②Structure  definition of doubly linked list

[Definition] The structure definition of the doubly linked list:

struct dbnode // 定义一个双向链表的结点结构体
{ 
    DataType data;                 // 数据域
    struct dbnode *prior, *next;   // 双向指针域
};
typedef struct dbnode *dbpointer;  // 定义一个指向 dbnode 的指针类型 dbpointer
typedef dbpointer Dlinklist;       // 定义一个指向 dbnode 的指针类型 Dlinklist
  • In this code, a structure dbnode is defined, which represents a node of a doubly linked list. It contains the data field data and two pointer fields prior and next. prior points to the predecessor node of the current node, and next points to the successor node of the current node.
  • Secondly, define a pointer type dbpointer pointing to the dbnode structure, which is used to point to the variable of the dbnode structure type.
  • Finally, rename dbpointer to Dlinklist with a typedef to indicate that Dlinklist is a pointer type to a dbnode.

[Node] The node of the doubly linked list:

  • The bidirectional circular linked list is suitable for applications where the predecessor and successor of the node need to be frequently searched
  • The complexity of finding the predecessor and successor are both: O(1)
[Example] Assume that p points to a node in the doubly linked list
  • Then p->prior->next is  equal   to  p->next->prior

③ Insertion of nodes in the doubly linked list

 [Explanation] To insert a new node *t after the node pointed to by p, 4 pointers need to be modified:

  • t->prior = p;
  • t->next = p->next;
  • p->next->prior = t;
  • p->next=t;

【Schematic Diagram】 

 

④ Deletion of nodes in the doubly linked list

[Explanation] Let p point to the node to be deleted, delete *p can be completed by the following statement:

  • p->prior->next = p->next;     // the back chain of the predecessor node of p points to the successor node of p
  • p->next->prior = p->prior;     // the front link of p's successor node points to p's predecessor node
  • free(p);                                 // release the space of *p
  • p->prior->next = p->next;   and  p->next->prior = p->prior;  The execution order of these two statements can be reversed

【Schematic Diagram】 

 



6. Comparison between sequence implementation and connection implementation 

(1) Advantages and disadvantages of linear list and linked list 

  • Each node of the singly linked list includes a data field and a pointer field, and the pointer field needs to occupy additional space
  • From the overall consideration, the sequence table needs to pre-allocate storage space. If the pre-allocation is too large, it will cause waste. If the allocation is too small, overflow will occur; the single-linked list does not need to pre-allocate space, as long as the memory space is not exhausted, There is no limit to the number of nodes in a singly linked list

(2) Comparison of time performance

sequence table linked list
read table element O(1) read table element O(n)
positioning (find x) O(n) positioning (find x) O(n)
insert O(n) insert O(n)
delete O(n) delete O(n)

Guess you like

Origin blog.csdn.net/qq_39720249/article/details/131414439