Time：2020-3-25

# Linear list – linked list

## Why are articles posted on holidays

//TODO NullGirlfrindException

Please ignore these two boring facts

## How to make up for the deficiency of sequence table?

The first time you learn linear table, you will immediately come into contact with a kind of order table (sequential storage structure). After the analysis of the previous article, the advantages and disadvantages of the order table are obvious. Although it can quickly access and read elements, it needs to move a large number of elements when solving operations such as insertion and deletion, which is inefficient. Is there a way to improve or How about solving this problem?

First of all, we need to consider why the insertion and deletion operations in the sequence table involve the movement of elements?

Good guy, the problem is around the biggest feature of the sequence table – sequential storage, adjacent placement of elements, that is, each element is next to each other according to the number, which leads to After inserting or deleting, in order to still store in order and linear, the position of the elements behind the operated elements needs to change. You can imagine that a scene of a student is suddenly inserted from the crowded team, and the huge crowd behind, with fragrant mouth, moves back an empty space. If the crowd is too large, it also needs a certain time to rearrange the team between

Well, don’t be so crowded between people. Everyone leaves a little space and leaves a certain position. OK, it seems to be a way, but a teacher who is responsible for communicating with students and filling in the form doesn’t need to do it. This means that I need to run a lot more and waste a lot of time when I’m traversing (looking for people). If I don’t talk about this, the sports hall will No, you can’t put it in my small hall, which means that the complexity of space has increased a lot

We just focused on the basic premise of “queuing”, but the way we can think of is not very ideal, so we simply do not queue, can we have a better solution?

An effective way:

Let the students (elements) find their own position and stand at will, but you should know the position relative to the next student. This not only solves the problem of space, but also can access (traverse) the whole team (array) through this 22 contact way. Most importantly, insert and leave the students. Because there is no such queue between the students (elements), the adjacent special Point, so it won’t be said that too many students (elements) will only need to communicate with the two students before and after you insert the position. Anyway, others don’t know what happened between you

OK. Let’s take a look at one of the most common linked lists: single linked list

## Basic structure of single chain table

Why is this kind of linked list called a single linked list? This is because it contains only one address field. What does that mean?

We have abandoned the one-stop queuing method in the list, but we have to let two elements that should be adjacent have a certain relationship with each other, so we choose to let each element contact the corresponding next element

At this time, we need to arrange an extra location for each element to store itsStorage address of subsequent elements, the domain for storing element information is calledPointer field or address field, the information stored in the pointer field is also calledPointer or chain

Let’s take a look at his structure with a picture

Explanation of nouns in structure

• Head pointer:A pointer variable to the address of the first node

• The head pointer hasIdentification single chain tableSo we often use the head pointerRepresents the name of a single chain table
• Head node:A node is attached before the first node of a single chain table. It has no direct precursor. It is called the head node

• It can be used as a surveillance post or for storing additional information such as the length of linear table
• Address of the primary node in the pointer field
• First element node:Node that stores the first element

## Why to attach a header node

Let’s explain:

• If the linked list is empty, if there is no head node in the single linked list, the head pointer will point to null. If the head node is added, the head pointer will point to the head node no matter whether the single linked list is empty or not, so that the processing of empty linked list and non empty linked list is consistent
• When inserting or deleting elements in front of the first element node, the operation is the same as that in the back, and no additional judgment branch is needed, which makes the algorithm simpler

(taking insertion as an example) in the case of a leading node, the operation of inserting or deleting elements in front of the first element node is still the same as that in other locations. You only need to point the pointer field of the previous element (in this case, the head node) to the inserting element, and point the pointer field of the inserted element to the original second element

In the case of headless nodes, because there is no element in front of the first element node, the front and back relationship of the head can only be modified, which leads to different operations of inserting or deleting elements in other locations. When these two functions are implemented, an additional judgment statement needs to be written to determine whether the inserted location is the position in front of the first element node, adding branches, and the code is not concise enough

Summary: the existence of the head node makes the processing of the empty list and the non empty list consistent, and also facilitates the insertion or deletion of the front node of the head node of the list

## Type definition of single chain table

### Abstract data type definition of linear table

Before we give the definition of single linked table, we need to introduce the abstract data type definition of our linear table

``````#ifndef _LIST_H_
#define _LIST_H_
#include<iostream>
using namespace std;

class outOfRange{};
template<class T>
class List {
public:
//Clear linear table
virtual void clear()=0;
//Null, table null returns true, non null returns false
virtual bool empty()const=0;
//Find the length of linear table
virtual int size()const=0;
//I n the linear table, insert the element value at the position of I [0.. n]
virtual void insert(int i,const T &value)=0;
//I n a linear table, elements are deleted at the position of I [0.. n-1]
virtual void remove(int i)=0;
//In a linear table, find the first occurrence of a value element
virtual int search(const T&value)const=0;
//In the linear table, find the element with bit order I and return its value
virtual T visit(int i)const=0;
//Ergodic linear table
virtual void traverse()const=0;
//Inverse linear table
virtual void inverse()=0;
virtual ~List(){};
};

/*Custom exception handling class*/

Class outofrange: public exception {// used to check the validity of the range
public:
const char* what() const throw() {
return "ERROR! OUT OF RANGE.\n";
}
};

Class badsize: public exception {// used to check the validity of length
public:
const char* what() const throw() {
}
};

#endif``````

### Type definition of single chain table

``````#ifndef _SEQLIST_H_
#define _SEQLIST_H_
#include "List.h"
#include<iostream>
using namespace std;

template<class elemType>
//ElemType is single chain table storage element type
private:
//Node type definition
struct Node {
//Data domain of the node
elemType data;
//Pointer field of node
Node *next;
//Two constructors
Node(const elemType value, Node *p = NULL) {
data = value;
next = p;
}
Node(Node *p = NULL) {
next = p;
}
};

//Head pointer of single chain table
//Tail pointer of single chain table
Node *tail;
//Current length of single chain table
int curLength;
//Returns a pointer to a node with bit order I
Node *getPostion(int i)const;
public:
//Empty a single linked table to make it empty
void clear();
//Single chain table with leading node, null
bool empty()const {return head -> next == NULL;}
//Returns the current actual length of a single chain table
int size()const {return curLength;}
//Add 1 to the node table with value inserted at bit order I
void insert(int i, const elemType &value);
//Delete node with bit order I, table length minus 1
int search(const elemType&value)const;
//Find the bit order of the precursor of the node with value
int prior(const elemType&value)const;
//Access the value of the node with bit order I, 0 to the first element node
elemType visit(int i)const;
//Ergodic single chain table
void traverse()const;
//Creating single chain table by head inserting
//Creating a single chain table by tailing
void tailCreate();
//Inverted single chain table
void inverse();
};``````

## Basic operation realization on single chain table

### （1） Initialization constructor of single chain table

The initialization of single chain table is to create aLead nodeOfEmpty linked list, we don’t need to set its pointer field, just leave it blank

``````template<class elemType>
head = tail = new Node();
curLength=0;
}``````

Note: the new operator represents the heap memory space to be applied for. The above code should judge whether the application is successful. It is simple and the default is successful. In fact, if the system does not have enough memory to use, a bad “alloc exception will be reported when applying for memory

### （2） Destructor

When a single chain table object is out of its scope, the system automatically executes a destructor to free the single chain table space, which is to empty the contents of the single chain table and release the header node

``````template<class elemType>
clear();
}``````

### （3） Clear single chain table

The main idea of clearing the single chain table is to release the later nodes gradually from the beginning of the first node, but we don’t want to easily change the direction of the head pointer, so we introduce a working pointer, move the first node all the way to the end of the table, and gradually release the nodes

``````template<class elemType>
Node *p, *tmp;
while(p != NULL) {
tmp = p;
p = p -> next();
delete tmp;
}
curLength = 0;
}``````

### （4） Find the length of the table

Because a variable called curlength has been defined in our code to record our table length

So we can go straight back and we’ve implemented it in the definition, which is this sentence

``````//Returns the current actual length of a single chain table
int size()const {return curLength;}``````

But if we don’t have such a variable, what kind of method do we want to achieve such a function?

``````template<class elemType>
Node *p = head -> next;
int count;
while(p) {count++; p = p -> next;}
return count;
}``````

### （5） Ergodic single chain table

We need to access each node in the single chain table from the beginning to the end, and output the information of the data field

``````template<class elemType>
Node *p = head -> next;
cout << "traverse:";
while (p != NULL) {
cout << p -> date << " ";
p = p -> next;
}
}``````

### （6） Find the memory address corresponding to its element in bit order I

Set a moving working pointer and a counter count. Initially, P points to the head node. When pointer P moves to the next node, counter count + 1 until P points to the node with bit sequence I. Return to p

``````template<class elemType>
if(i < -1 || i > curLength - 1)
return NULL;
int count = 0;
while(count <= i) {
p = p -> next;
count++;
}
return p;
}``````

### （7） Query node order by value

Set a mobile working pointer and a counter count. Start from the first node of the single chain table and start to compare with the given value. If they are equal, the search succeeds and the bit order of the node is returned. Otherwise, continue to query until the single chain table ends and the query fails and – 1 is returned

``````template<class elemType>
Node *p = head -> next;
int count = 0;
while (p != NULL && p -> data != value) {
p = p -> next;
count++;
}
if (p == NULL) {
return -1;
}else {
return count;
}
}``````

### （8） Insert node

We need to find the node P whose bit order is I – 1, let the Q pointer field point to the successor of the original P, then change the successor of P to Q, that is to say, we can change the element pointing relationship before and after the insertion element position

``````template<class elemType>
void linkList<elemType>::insert(int i,const elemType &value) {
Node *p, *q;
if(i < 0 || i > curLength)
throw outOfRange();
p = getPostion(i - 1);
q = new Node(value,p -> next);
p -> next = q;
if (p == tail) tail = q;
curLength++;
}``````

### (nine) delete node

Can understand the method of adding nodes, and understand that deleting nodes is easy

``````template<class elemType>
//P is the node to be deleted, and pre is its precursor
Node *p, *pre;
if(i < 0 || i > curLength)
throw outOfRange();
pre = getPostion(i - 1);
p = pre -> next;
if (p == tail) {
tail = pre;
pre -> next = NULL;
delete p;
} else {
pre -> next = p -> next;
delete p;
}
}``````

## The creation of the whole single chain table

Looking back at the sequence table we have known before, it can be understood as an array. We declare a type, give a value at the same time, initialize its size, but the single chain table is not the same. It is a dynamic organization, it does not need to be like the sequence table in the same element set, it can dynamically generate nodes with the actual situation, so it does not need to pre allocate the space size and position

### （1） Creating single chain table by head inserting

Head insertion means that every time a new node is inserted behind the head node and before the first element node, you can understand that I’ll queue first, but when someone comes behind, he will queue in front of me. Let’s have a look at it with the help of the figure

We insert element 123 at a time, but what we output is stored in the order of 321, which is the opposite of our logical order

Let’s see how to achieve it

``````template<class elemType>
Node *p;
elemType value, flag;
cout << "inputelements, ended with:";
cin >> flag;
while(cin >> value, value != flag) {
//p -> data == value, p -> next = head ->next
p = new Node(value, head -> next);
//The original link list is empty, and the new node P becomes a node
tail = p;
curLength++;
}
}``````

#### Inverted single chain table

We know that the order of elements in the single chain table is opposite to the order of reading in. We can help us to restore our habitual thinking order through the algorithm of inverted single chain table

``````template<class elemType>
Node *p, *tmp;
//P is the working pointer, pointing to the initial node
//The pointer field of the head node is set to null to form a null list
//After inversion, the first node will become the tail node
if (p)
tail = p;
while (p) {
//The successor of temporary p
tmp = p -> next;
p -> next = head -> next;
//Node P is inserted after the head node
//Continue with next node
p = tmp;
}
}``````

### （2） Creating a single chain table by tailing

After reading the head inserting method, I feel that this kind of order is always a little awkward with our consistent thinking, and the tail inserting method is a kind of creation method that the logical order is consistent with ours

Let’s take a look at the picture below

``````template<class elemType>
Node *p;
elemType value, flag;
cout << "inputelements, ended with:";
cin >> flag;
while(cin >> value, value != flag) {
p = new Node(value,NULL);
tail -> next = p;
tail = p;
curLength++;
}
}``````

## Merge single chain table

Requirement: suppose we give two single chain tables La and LB, which are still increasing, and we combine them into LC to ensure increasing. We use the original table space, but we still call table C the new table below

Because our requirements are incremental, it is very suitable to use the tail interpolation method. We design three working pointers, pointing to the first element node of two tables respectively, and then point the third pointer to the head node of the new table. Compare the values pointed by the first two pointers, the smaller one will be placed at the tail of the new table, and then move the smaller one of the two tables, and so on until it is One of the remaining nodes is linked to the end of the new table

``````template<class elemType>
Node *pa, *pb, *pc;
pb = (lb -> head) -> next;
(lb -> head) -> next = NULL;

while(pa && pb) {
if(pa -> data <= pb -> data) {
pc-> next = pa;
pc = pa;
pa = pa -> next;
} else {
pc -> next = pb;
pc = pb;
pb = pb -> next;
}
}
if(pa) {
pc -> next = pa;
lc -> tail = tail;
} else {
pc -> next = pb;
lc -> tail = lb -> tail;
}
lc -> cuirLength = curLength + lb -> curLength;
delete lb;
return lc;
}``````

## summary

The single chain table adopts the chain storage structure to store the elements of the linear table with a group of arbitrary storage units, which is more suitable for frequent insertion and deletion of data. If frequent search or recommended use of the sequence table is needed, for example, for the production of a student’s score management system, students often check their own scores, but enter them Teacher, only input once after the exam, so you should use the sequence table. For example, the attendance punch system is more about the record of punch information, so you should choose to use the chain table. Of course, the example may not be very appropriate. At the same time, there will be more complex problems to consider in the normal development. The example is only for the convenience of understanding