# Basic notes of data structure - Chapter 2 linear table

## Chapter II linear table

### 2.1 type definition of linear table (logical structure)

The concept of linear table: a finite sequence of data elements with the same characteristics

Conceptual description of linear table:

• The logical structure of data refers to the logical structure between data elements, which is established by users according to their needs
• The logical structure definition of linear table is unique and independent of computer
• The linear structure reflects the logical relationship between nodes, which is one-to-one
• A one-dimensional vector is a linear table, and a two-dimensional or N-dimensional array is still a linear table

### 2.2 sequential representation and implementation of linear table (storage structure)

#### 2.2.1 representation of sequence table:

Sequential storage definition: a storage structure that stores logically adjacent data elements in physically adjacent storage units

Sequential storage method: a set of storage units with continuous addresses are used to store the elements of the linear table in turn

Sequential storage characteristics of linear table:

• Logically adjacent data elements are also physically adjacent
• If the location of the first element in the table in the memory is known, the storage location of other elements can also be obtained

"Sequence table is a random access storage structure" -- meaning: the time performance of searching on the storage structure such as sequence table is O (1)

Storage structure and access structure are two different concepts:

• Storage structure is the representation of data and its logical structure in computer
• An access structure is a description of the temporal performance of a lookup operation on a data structure (such as random access or sequential access)

#### 2.2.2 implementation of sequence table:

```#include<iostream>
#include<stdlib.h>
using namespace std;

//The macro constant defines the length of the linked list
#define LISST_INIT_SIZE 100
//Macro constants define the growth of linked lists
#define LISTINCREMENT 10

typedef  int ElemType;
typedef  int Status;

//Define linear table
typedef struct{
int* elem;  //Define storage base address
int length;  //Current sequence table length
int listsize;  //Current allocation size
}SqList;

cout<<"---- 1.Initialize linked list ---------------"<<endl;
cout<<"---- 2.Destroy linked list -----------------"<<endl;
cout<<"---- 3.Empty linked list -----------------"<<endl;
cout<<"---- 4.Determine whether the linked list is empty ---------"<<endl;
cout<<"---- 5.Find the length of the linked list ---------------"<<endl;
cout<<"---- 6.Gets the element at the specified location in the linked list ---" <<endl;
cout<<"---- 7.Get linked list element location ---------"<<endl;
cout<<"---- 8.precursor ---------------------"<<endl;
cout<<"---- 9.Successor ---------------------"<<endl;
cout<<"---- 10.Insert an element at the specified position in the linked list --"<<endl;
cout<<"---- 11.Delete the element at the specified position in the linked list ----"<<endl;
cout<<"---- 12.Display linked list ----------------"<<endl;
cout<<"---- 13.Merge two non decreasing ordered linked lists "<<endl;
cout<<"---- 14.Exit (enter a negative number) ----"<<endl;
}

//Initialize build
void IntList(SqList &L){
L.elem=(ElemType *)malloc(LISST_INIT_SIZE*sizeof(ElemType));
if(!L.elem)
{
cout<<"Linked list initialization failed"<<endl;
}
L.length=0;
L.listsize=LISST_INIT_SIZE;
if(L.elem){
cout<<"The linked list was initialized successfully"<<endl;
}

}
//Destroy linear table
void DestoryList(SqList &L){
free(L.elem);
L.elem=NULL;
cout<<"The linked list was destroyed successfully"<<endl;

}
void ClearList(SqList &L){
if(!L.elem)
{
cout<<"Linked list not initialized!"<<endl;
}
else{
L.length=0;
cout<<"Empty successfully"<<endl;
}
}
void Kong(SqList &L){
if(L.length==0){
cout<<"The linear table length is empty"<<endl;
}
else cout<<"The length of the linear table is not empty, its length is"<<L.length<<endl;
}

void Length(SqList &L){
cout<<"The length of the linear table is"<<L.length<<endl;
}

void GetElem(SqList &L,int i){
if(i<1||i>L.length){
cout<<"This location is illegal and cannot be accessed"<<endl;
}
else
cout<<"The first"<<i<<"The element at position is"<<L.elem[i-1];
}

void Locate(SqList &L,int e){
int i,note1=0,note2=0;
for(i=0;i<L.length;i++){
if(e==L.elem[i]){
cout<<"The element location is"<<i+1<<endl;
note1=1;
}
else note2=2;
}
if(note1==0&&note2==0){
}

}

int Qianqu(SqList &L,int e){
int i;
for(i=0;i<L.length;i++){
if(e==L.elem[i]){
return L.elem[i-1];
}
}
return 0;
}

int Houji(SqList &L,int e){
int i;
for(i=0;i<L.length;i++){
if(e==L.elem[i]){
return L.elem[i+1];
}
}
return 0;
}

void Insert(SqList &L,int e,int i){
if(i<1||i>L.length+1){
cout<<"Insert failed"<<endl;
}
else if(L.length==L.listsize){
cout<<"The linked list is full"<<endl;
}
else{
for(int j=i-1;j<L.length+1;j++){
L.elem[j+1]=L.elem[j];
}
L.length++;
L.elem[i-1]=e;
cout<<"Insert successful"<<endl;
}
}
void shanchu(SqList &L,int i){
if(i<1||i>L.length){
cout<<"Deletion failed"<<endl;
}
else{
for(int j=i-1;j<L.length;j++){
L.elem[j]=L.elem[j+1];
}
L.length--;
cout<<"Delete succeeded"<<endl;
}
}
void show(SqList &L){
cout<<"The linear table element is";
for(int i=0;i<L.length;i++){
cout<<L.elem[i]<<" ";
}
}

//Encapsulates a function that combines two linear tables
void Combine(SqList &L1,SqList &L2,SqList &L3){
int i=0;
int j=0;
int k=0;
int a,b;
int length1=L1.length,length2=L2.length;
while(i<length1&&j<length2){
a=L1.elem[i];
b=L2.elem[j];
if(a<b){
L3.elem[k]=a;
L3.length++;
k++;
i++;
}
else if(a==b){
L3.elem[k]=a;
k++;
i++;
j++;
L3.length++;
}
else{
L3.elem[k]=b;
L3.length++;
k++;
j++;
}
}

while(i<length1){
a=L1.elem[i];
L3.elem[k]=a;
L3.length++;
k++;
i++;
}
while(j<length2){
b=L2.elem[j];
L3.elem[k]=b;
L3.length++;
k++;
j++;
}
show(L3);
}

int main(){
int a,i,e;
SqList L;
SqList L1;
SqList L2;
SqList L3;
while(1){
system("cls");
cin>>a;
switch(a){
case 1:IntList(L);
system("pause");
break;

case 2:
if(!L.elem)
{
}
else{
DestoryList(L);
}
system("pause");
break;

case 3:
if(!L.elem)
{
}
else
{
ClearList(L);
}
system("pause");
break;

//Determine whether the linked list is empty
case 4:
if(!L.elem)
{
}
else{
Kong(L);
}
system("pause");
break;

//Output linked list length
case 5:
if(!L.elem)
{
}
else{
Length(L);
}
system("pause");
break;

//Gets the position of the specified element in the linked list
case 6:
if(!L.elem)
{
}
else{
cout<<"Please enter the location of the element you want to find"<<endl;
cin>>i;
GetElem(L,i);
}
system("pause");
break;

//Gets the position of the specified element in the linked list
case 7:
if(!L.elem)
{
}
else{
cout<<"Please enter the element you want to query"<<endl;
cin>>e;
Locate(L,e);
}
system("pause");
break;

//Gets the precursor of the specified element
case 8:
if(!L.elem)
{
}
else{
cout<<"Please enter an element"<<endl;
cin>>e;
int a = Qianqu(L,e);
if(a==0){
cout<<"Element does not exist!"<<endl;
}else{
cout<<"The precursor of this element is"<<a<<endl;
}
}
system("pause");
break;

//Gets the successor of the specified element
case 9:
if(!L.elem)
{
}
else{
cout<<"Please enter an element"<<endl;
cin>>e;
int b = Houji(L,e);
if(b==0){
cout<<"Element does not exist!"<<endl;
}
else{
cout<<"This element is followed by"<<b<<endl;
}
}
system("pause");
break;

//Insert an element at the specified position in the linked list
case 10:
if(!L.elem)
{
}
else{
cout<<"Please enter the element you want to insert"<<endl;
cin>>e;
cout<<"Please enter the location where you want to insert the element"<<endl;
cin>>i;
Insert(L,e,i);}
system("pause");
break;

//Delete the element at the specified position in the linked list
case 11:
if(!L.elem)
{
}
else{
cout<<"Please enter the location you want to delete"<<endl;
cin>>i;
shanchu(L,i);
}
system("pause");
break;

case 12:
if(!L.elem)
{
}
else
{
show(L);
}
system("pause");
break;

//Merge two non decreasing ordered linked lists
case 13:
IntList(L1);
IntList(L2);
IntList(L3);
cout<<"Please enter the length of the first linked list"<<endl;
cin>> L1.length;
cout<<"Please enter the element of the first linked list"<<endl;
for(i=0;i<L1.length;i++){
cin>>L1.elem[i];
}
cout<<"Please enter the length of the second linked list"<<endl;
cin>>L2.length;
cout<<"Please enter the element of the second linked list"<<endl;
for(i=0;i<L2.length;i++){
cin>>L2.elem[i];
}
Combine(L1,L2,L3);
system("pause");
break;
}
}
}
```

#### 2.2.3 operation efficiency analysis of sequence table:

Time efficiency analysis: the algorithm time is mainly consumed in the operation of moving elements, so the basic operation for calculating time complexity (deepest statement frequency) T (n) = O (number of moving elements)

The number of elements moved depends on where the element is inserted or deleted

• If the element is inserted before the I position of the linear table with length N, the number of elements moved backward is: f(n)=n-i+1
• If the element is deleted at position I of the linear table with length N, the number of elements moved forward is: f(n)=n-i

Assuming that the insertion and deletion of elements at any position in the table are equal probability, the insertion probability p(i) = 1/(n+1), and the deletion probability p(i) = 1/n, then:

Insertion operation time efficiency (average number of moves): n/2

Delete operation time efficiency (average moves): (n-1)/2

Therefore, time complexity T (n) = O (n)

Spatial complexity of sequential table S (n) = O (1)

### 2.3 chain representation and implementation of linear table (storage structure)

#### 2.3.1 representation of linked list

Chain storage features: logically adjacent, physically not necessarily adjacent

1. Each storage node contains two parts: data field and pointer field (chain field)
2. In a single linked list, except for the first node, the storage location of any node is indicated by the value of the chain field of its direct precursor
• The linked list with only one pointer field is a single linked list
• A linked list with two pointer fields is a double linked list
• The linked list with head and tail is a circular linked list

Header pointer, header node and primitive node:

The header pointer is a pointer to the first node of the linked list (or a pointer to the header node / first element node)

The first element node refers to the node that stores the first data element of the linear table in the linked list

The head node is a node attached before the first node of the linked list. Only the empty table flag and table length information are stored in the data field

Question 1: how to represent an empty table

When there is no header node, when the value of the header pointer is null, it indicates an empty table

When there is a header node, when the pointer field of the header node is empty, it indicates an empty table

Question 2: what are the benefits of setting header nodes in the linked list

The head node is a node attached before the first element node of the linked list. No data elements are stored in the data field of the node. No matter whether the linked list is empty or not, the head pointer is always empty. Its function is to uniformly deal with the situation of empty tables, non empty tables and longevity nodes when operating the linked list

1. For the linked list of the leading node, to insert or delete a node before any node in the table, all you have to do is modify the pointer field of the previous node, because any element node has a precursor node. If there is no head node, that is, the first element node has no precursor node, the operation will become complex
2. For the linked list of the leading node, the header pointer refers to the non null pointer to the leading node, so the processing of null table and non null table is the same. In this way, we can distinguish between null linked list and null pointer, and reduce the complexity of the program and the chance of bug s

For example, when deleting, L is the header pointer, p pointer points to the deleted node, and q pointer points to the precursor of the deleted node. For a non empty single linked list:

1. When taking the lead node

Delete the first node (q points to the head node): q - > next = P - > next;

freeĀ§;

Delete the ith node (i is not equal to 1): Q - > next = P - > next; free§;

2. Do not take the lead node

When deleting the first node (q is empty): l = P - > next; free§;

Delete the ith node (i is not equal to 1): Q - > next = P - > next; free§;

When the lead node is deleted, the code used is the same regardless of which node is deleted; When you do not take the lead node, the code used to delete the first element is different from that used to delete elements in other locations, which is relatively troublesome

#### 2.3.2 implementation of linked list

Implementation of single linked list:

```#include<iostream>
#include<cstring>
#include<stdio.h>
#include<stdlib.h>

#define LEN sizeof(Stu)

using namespace std;

typedef struct student{
int data;
struct student *next;
}Stu;

void Tips()
{
cout << "The following actions can be performed:" << endl;
cout << "*********************************************************" << endl;
cout << "***************  1.Initialize or reset linked list      ****************" << endl;
cout << "***************  2.Destroy linked list              ****************" << endl;
cout << "***************  3.Empty linked list              ****************" << endl;
cout << "***************  4.Return linked list length          ****************" << endl;
cout << "***************  5.Element at specified location        ****************" << endl;
cout << "***************  6.The bit order of elements already exists in the linked list  ****************" << endl;
cout << "***************  7.Find the direct precursor of the input element  ****************" << endl;
cout << "***************  8.Find the direct successor of the input element  ****************" << endl;
cout << "***************  9.In the first i Insert an element at a location **************" << endl;
cout << "***************  10.Delete paragraph i Elements        ****************" << endl;
cout << "***************  11.Output some linked list elements     ****************" << endl;
cout << "***************  12.Initialize and input elements using head interpolation (or tail interpolation)*" << endl;
cout << "***************  13.Realize the reverse storage of single linked list ****************" << endl;
cout << "*********************************************************" << endl;
}

Stu* InitList(){
Stu *p;
p=(Stu*)malloc(LEN);
if(p==NULL){
cout<<"Memory allocation failed!"<<endl;
return 0;
}
//Null the tail node pointer to represent the end of the linked list
p->next=NULL;
return p;
}

//Destroy linked list function
void Destory(Stu* S){
Stu *p;
p=NULL;
while(S){
p=S;
S=S->next;
free(p);
}
}

//Empty linked list function
int Clear(Stu *S){
Stu* p=S->next;
while(p!=NULL){
Stu * q=p->next;
delete p;
p=q;
}
S->next=NULL;
return 0;
}

//Linked list length function
int Length(Stu *S){
Stu *p;
int j=0;
p=S;
while(p->next){
j++;
p=p->next;
}
return j;
}

//Insert element function
int Insert(Stu *S,int n,int e){
Stu *p,*s;
int j=0;
//Insert element: 1. Find the insertion position 2. Apply for the space of the insertion node 3. Change the direction of the two pointers
p=(Stu*)malloc(LEN);
s=S;
while(s && j<n-1){
j++;
//Find the element location and represent it with j
s=s->next;
}
if(!s){
return -1;
}
if(p==NULL){
cout<<"Failed to apply for memory space!"<<endl;
}
p->data=e;
//Change the direction of two pointers
p->next=s->next;
s->next=p;
return 0;
}

//Display linked list element function
void Show(Stu *S,int l){
Stu* p;
p=S->next;
for(int i=1;i<=l;i++){
cout<<"The first "<<i<<" Elements:"<<p->data<<endl;
p=p->next;
}
}

//Element at specified location
int GetElme(Stu *S,int n){
Stu *p;
p=S->next;
int j;
//Find bit order
while(p && j<n-1){
p=p->next;
j++;
}
return p->data;
}

//The bit order of the element already exists
int FindElme(Stu *S,int e){
Stu *p;
p=S->next;
int j=1;
//Traverse linked list elements
while(p->next){
if(p->data==e){
return j;
}else{
return -1;
}
p=p->next;
j++;
}
return 0;
}

//Find the direct precursor of the specified element
int QianQu(Stu *S,int e){
//The methods to find the predecessor and successor: 1. Traverse the linked list according to the incoming element to find the position of the previous node of the element node. 2. Output the data field of this node
Stu *p;
p=S->next;
if(e==p->data){
return -1;
}
while(p->next){
p=p->next;
if(p->next->data==e){
return p->data;
}else{
return 0;
}
}
return 0;
}

//Find the direct successor of the specified element
int HouJi(Stu *S,int e){
Stu *p;
p=S->next;
if(!p->next){
return 0;
}
while(p->next){
if(p->data==e){
return p->next->data;
}else{
return -1;
}
p=p->next;
}
return -1;
}

//Deletes the element at the specified location
int Delete(Stu *S,int n){
//First, find the element at the specified location
Stu *p,*q;
p=S;
int j=0;
while(p->next && j<n-1){
j++;
p=p->next;
}
q=p->next;//Use q to store the next node of p
p->next=q->next;//At this time, p points to the next of the original p
free(q);//Release q again, that is, delete the next of the original p
return -1;
}

//Reverse order storage of linked list elements
void NiXu(Stu *S){
Stu *p,*q;
p=S->next;
S->next=NULL;       //The thought of head inserting method
while(p!=NULL){      //Use q and p to record the first and second nodes
q=p;
p=p->next;
q->next=S->next;
S->next=q;
}
int l = Length(S);
Show(S,l);
}

//Encapsulate main function
int  main(){
Stu *S=NULL;
while(true){
int n;
Tips();
cout<<"Please enter service number:"<<endl;
cin>>n;
switch(n){
case 1:{
S=InitList();
if(S){
cout<<"The linked list was created successfully!"<<endl;
}
break;
}
case 2:{
if(!S){
cout<<"No linked list to destroy!"<<endl;
}else{
Destory(S);
S=NULL;
cout<<"Destroy linked list successfully!"<<endl;
}
break;
}
case 3:{
if(!S){
cout<<"There is no linked list to empty!"<<endl;
}else{
if(Clear(S)==0){
cout<<"The linked list is cleared successfully!"<<endl;
}
}
break;
}
case 4:{
if(!S){
}else{
int a=Length(S);
cout<<"The length of the linked list is:"<<a<<endl;
}
break;
}
case 5:{
if(!S){
}else{
cout<<"Please enter the element bit order:";
int n;cin>>n;
if(n>Length(S)){
cout<<"Illegal location!"<<endl;
break;
}
int e=GetElme(S,n);
cout<<endl;
cout<<"Elements of this bit order:"<<e<<endl;
}
break;
}
case 6:{
if(!S){
}else{
cout<<"Please enter the element to query bit order:";
int e;cin>>e;
cout<<endl;
int c = FindElme(S,e);
if(c==-1){
cout<<"The element does not exist in the linked list!"<<endl;
}
cout<<"Bit order of this element:"<<c<<endl;
}
break;
}
case 7:{
if(!S){
}else{
cout<<"Please enter the element whose direct precursor you want to view:";
int e;cin>>e;
cout<<endl;
int d = QianQu(S,e);
if(d==-1){
cout<<"The head node of the linked list has no direct precursor!"<<endl;
break;
}
else if(d==0){
cout<<"Abnormal operation! The query location may be illegal!"<<endl;
}else{
cout<<"Direct precursor of this element:"<<d<<endl;
}
}
break;
}
case 8:{
if(!S){
}else{
cout<<"Enter the element whose immediate successor you want to view:";
int e;cin>>e;
cout<<endl;
int d = HouJi(S,e);
if(d==0){
cout<<"The tail node of the linked list has no direct successor!"<<endl;
break;
}else if(d==-1){
cout<<"Abnormal operation! The query location may be illegal!"<<endl;
}
else{
cout<<"Direct successor of this element:"<<d<<endl;
}
}
break;
}
case 9:{
if(!S){
}else{
int a=Length(S);
cout<<"Current linked list length:"<<a<<"  Please select the location where you want to insert the element:";
int n;cin>>n;cout<<endl;
if(n>Length(S)){
cout<<"Illegal insertion position!"<<endl;
break;
}
cout<<"Please enter the element value:";
int e;cin>>e;
int b=Insert(S,n,e);
if(b==-1){
cout<<"Element insertion failed!"<<endl;
}else{
cout<<"Element inserted successfully!"<<endl;
}
}
break;
}
case 10:{
if(!S){
}else{
int n;
cout<<"Please enter the location of the element to delete:";
cin>>n;
if(n>Length(S)){
cout<<"Illegal insertion position!"<<endl;
break;
}
int a = Delete(S,n);
if(a==-1){
cout<<"Delete succeeded!"<<endl;
}else{
cout<<"Abnormal operation! "<<endl;
}

}
break;
}
case 11:{
if(!S){
}else{
int l = Length(S);
Show(S,l);
}
break;
}
case 12:{
if(!S){
}else{
cout<<"Please enter the initial number of elements:";
int m;cin>>m;
cout<<endl;
int start = Length(S) + 1;
for(int i=0;i<m;i++){
cout<<"Please enter the element value:";
int e;cin>>e;
Insert(S,start+i,e);
}
cout<<"The linked list element is initialized successfully!"<<endl;
}
break;
}
case 13:{
if(!S){
}else{
cout<<"Storage results of single linked list in reverse order:"<<endl;
NiXu(S);
}
break;
}
}
system("pause");
system("cls");
}
}
```

Circular linked list: the pointer field of the last node in the list points to the head node, and the whole linked list forms a ring

• The implementation of circular linked list does not need to increase the storage capacity. Only a slight change in the link mode of the table can make the table processing more convenient and flexible. Other nodes in the table can be found from any node
• The operation of circular linked list is basically the same as that of linear linked list. The difference is that the circular condition in the algorithm is not whether o or P - > next is empty, but whether they are equal to the header pointer

Double linked list: the node has two pointer fields, one pointing to the direct predecessor and the other pointing to the direct successor

• It overcomes the disadvantage of unidirectionality of single linked list (query successor O (1), query precursor O (n))
• The bidirectional linked list is uniquely determined by the head pointer head
• When inserting and deleting a two-way linked list, you must modify the pointers in both directions at the same time

#### 2.3.3 operation efficiency analysis of linked list

Time efficiency analysis:

1. Search: because the linear linked list can only be stored sequentially, that is, the search should start from the node, and the time complexity of the search is O (n)
2. Insert and delete: linear linked list does not need to move elements. After giving the appropriate pointer, the time required for insert and delete operations is only O (1)

Space efficiency analysis:

Each node in the linked list needs to add a pointer space, which is equivalent to adding n integer variables in total, and the space complexity is O(n)

practice:

1. Logical structure characteristics of linear table: there is only one head node and tail node. Except for the head and tail nodes, other nodes have only one direct precursor and one direct successor. In short, the linear structure reflects that the logical relationship between nodes is one-to-one

2. Characteristics of sequential storage structure and chain storage structure of linear table:

During sequential storage, the storage addresses of logically adjacent data elements are also adjacent (logical and physical unity)

In chain storage, logically adjacent data elements can be stored at will, and the storage address of the data field of the next node is indicated by the value of the pointer field of the previous node (the storage space of each node is divided into two parts, one part stores the node value and the other part stores the pointer representing the relationship between nodes)

3. Advantages and disadvantages of sequential storage structure and chain storage structure:

The advantages of sequential storage structure are high density and high utilization of storage space, while the disadvantages are inconvenient operation of addition and deletion

The advantages of chain storage structure are convenient addition and deletion operation and flexible use. The disadvantages are small storage density and low utilization of storage space

(in fact, the speed of the linked list addition and deletion operation is in exchange for time at the cost of space. Storage density = the storage occupied by the node data itself / the total storage occupied by the node structure)

4. The pointer field in the static linked list stores the subscript of the next element in the array

5. A single linked list with a length of n is provided with two pointers at the beginning and end. When deleting the single linked list, the length of the last element of the list will change

6. Compared with single linked list, the advantage of two-way linked list is that it is more flexible to access adjacent nodes in sequence

7. Compared with single linked list, circular linked list has the advantages of random access

Posted on Sun, 28 Nov 2021 06:52:57 -0500 by alsinha