# Algorithm and data structure [C + +]: sparse table

Keywords: network

### In many situations, the best way to store data is tables.

Array is the best choice when the data is densely clustered in a certain coordinate range.
For example, to store the scores of students in a class, there are 30 students in the class, numbered from 1-30, 10 courses, numbered from 1-10
Then you can use an array of 30x10 to store this score sheet, which is economical and convenient to use

But sometimes the data is very sparse. For example, a school has opened 1000 courses, and some students can choose courses at will. Now, a data structure is needed to store the scores of each student in each course.
Obviously, a student can only take more than ten courses a semester, so the data in the table is very sparse, most of the nodes are empty nodes, without data. If you use arrays, you need to allocate space in advance, not only the score table itself is very large, but also a lot of space is wasted.

## At this point, you can use sparse tables.

Imagine now that there is a record of 3000 students in 1000 subjects.
Now we abstract every non empty table element into a node. Each column is strung up to form many columns, which are put into an array together. Each row is strung up to form many rows, which are put into an array together. In this way, the nodes selected from the whole dense array are weaved into a sparse net.
Just maintain and store this network

The following picture: ### The attributes of the sparse table are as follows:

int rowTotalNum; / / total rows
int colTotalNum; / / total columns
LinkedList[] row; / / the pointer of the row list. The size should be the same as the following
LinkedList[] col; / / the pointer of the column list. The size should be the same as the following

### The sparse table provides the following methods:

SparseTable(): constructor, initialization parameter
Void insert (int value, int rowIndex, int colIndex): inserts a value into a point (rowIndex, colIndex) of the sparse table
void remove(int rowIndex, int colIndex): delete the node of a coordinate (rowIndex, colIndex)
int getValue(int rowIndex, int colIndex): get the value of the specified coordinate (rowIndex, colIndex). If there is no such node, return - 1. There are two methods inside the method, by column and by row
void printSelfByRow(): print sparse table through row linked list
void printSelfByCol(): print sparse table through column linked list

LinkedList getCol(int colIndex): get the column list of a column
LinkedList getRow(int rowIndex): get the row list of a row

Here is the C + + Code:

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

//Node class, representing the nodes of the linked list
class Node{
public:
int row;
int col;
int value;	//Value of storage node
Node* next;	//Store next node's pointer

Node(int aValue, int aRow, int aCol, Node* aNext = NULL){	//Constructor, the value of the node must be passed in, and the next node defaults to NULL
this->value = aValue;
this->next = aNext;
this->row = aRow;
this->col = aCol;
}
};

class LinkedList{	//Common unidirectional list class
public:
int length;		//The length of the linked list is not important. It is not used in the following methods, but it is maintained
Node* tail;		//Pointer to the node at the end of the list
length = 0;
}

//Treat the list as a list of columns, and insert the node at row row with value
void insertToCol(int value, int row, int col){
//Search in col where nextCol > col
//Find the node whose coordinate is row in a column, and return the value of the previous node of the node
//The returned results are as follows
//1. NULL: indicates that the node is found and it is the head node, so there is no precursor node;
//2. NULL: the list is empty
//3. It is not empty, indicating that the precursor node is found, and the basis is that the coordinates of the successor node are larger than the coordinates to be inserted
//insertNode in that position

//If the link list is empty and NULL is returned, the node needs to be inserted in the first position to update the head and tail
if (aheadOfInsert == NULL && isEmpty()){
head = tail = new Node(value, row, col);
}
//If NULL is returned and the linked list is not empty, the first node should be added and the head should be updated
else if (aheadOfInsert == NULL && !isEmpty()){
}
//Otherwise, insert normally
else {
}
length++;
}

//Similarly, insert a node into the col coordinate of the row list
void insertToRow(int value, int row, int col){
//Search in col where nextCol > col

//insertNode in that position
if (aheadOfInsert == NULL && isEmpty()){
head = tail = new Node(value, row, col);
}
else if (aheadOfInsert == NULL && !isEmpty()){
}
else {
}
length++;
}

//Take the current linked list as a column linked list, and delete the node whose coordinate is row
void deleteByCol(int row, int col){
//Search in col where nextCol > col
//Search for the precursor node to delete
//The returned results are as follows
//1. NULL: indicates that the node is found and it is the head node, so there is no precursor node;
//2. NULL: the list is empty
//4. It is not empty, indicating that the precursor node is found, and the basis for finding is that the coordinates of the successor node are larger than the coordinates to be inserted, so the successor node is not necessarily the node to be deleted

Node* deletedNode=NULL;
//Case 1: it may be necessary to delete the head node and compare the coordinates. If it is necessary to delete it, delete the head node and update the head
if (aheadOfDelete == NULL && !isEmpty()
length--;
}
//Cases 2 and 3: no node found to delete, return
return ;
//Case 3: no node found to delete, return
return ;
//Otherwise, delete the node normally
length--;
}
//Free the memory of this node
delete deletedNode;
}

//Take the current linked list as a row linked list, and delete the node whose coordinate is col
//Empathy
void deleteByRow(int row, int col){
//Search in col where nextCol > col
//cout<<"deleting by row"<<endl;

Node* deletedNode=NULL;
if (aheadOfDelete == NULL && !isEmpty()

length--;
}
return ;

return ;
length--;
}

delete deletedNode;
}

//According to the column, find the value of the coordinate (row, col)
int getValueByCol(int row, int col){
//Search in col where nextCol > col
//Search for the precursor node to find
//The returned results are as follows
//1. NULL: this node is found and it is the head node, so there is no precursor node;
//2. NULL: this node is not found, which means that the list is not empty but NULL is returned;
//3. NULL: the list is empty
//5. It is not empty, indicating that the precursor node is found, and the basis for finding is that the coordinates of the successor node are larger than the coordinates to be inserted, so the successor node is not necessarily the node to be deleted

//Situation 1
if (aheadOfNode == NULL && !isEmpty()
}
//Situation 2
else if (aheadOfNode == NULL && !isEmpty())
return -1;
//Situation 3
return -1;
//Situation 4
return -1;
//Situation 5
}
return -1;
}

//Find the value of the coordinate (row, col) according to the row
int getValueByRow(int row, int col){
//Search in col where nextCol > col
//Search for the precursor node to find
//The returned results are as follows
//1. NULL: indicates that the node is found and it is the head node, so there is no precursor node;
//2. NULL: the list is empty
//4. It is not empty, indicating that the precursor node is found, and the basis for finding is that the coordinates of the successor node are larger than the coordinates to be inserted, so the successor node is not necessarily the node to be deleted

//Situation 1
if (aheadOfNode == NULL && !isEmpty()
}
//Situation 2
else if (aheadOfNode == NULL && !isEmpty())
return -1;
//Situation 3
return -1;
//Situation 4
return -1;
//Situation 5
}
return -1;
}

//Take the current linked list as a column linked list and search the node whose row coordinate is row
Node* searchInCol(int row){
//return NULL if list is empty;
//If the link list is empty or the row coordinate of the head node is greater than the row coordinate of the node to be searched, return null
return NULL;
Node* now;
//Loop lookup
//There are two conditions for cycle termination:
//1. At the end of the list, it is still not found. Corresponding to now - > next! = null
//2. The row coordinate of the next node is smaller than the row coordinate to be searched, corresponding to now - > next - > row < row
for (now=head; now->next!=NULL && now->next->row<row; now=now->next);
return now;
}

//Empathy
//Take the current linked list as a row linked list, and search for nodes whose column coordinates are row
Node* searchInRow(int col){
//return NULL if list is empty;
return NULL;
Node* now;
for (now=head; now->next!=NULL && now->next->col<col; now=now->next);
return now;
}

int isEmpty(){			//Judge whether the chain list is empty or not. If the head pointer is 0, it means empty
}

void printSelf(){	//Print linked list content

}

};

//Sparse table
class SparseTable{
public:
int rowTotalNum;	//Total number of banks
int colTotalNum;	//Total column number
LinkedList* row;	//The pointer of the row list. The size should be the same as the following
LinkedList* col;	//Pointer to the column list, the size should be consistent with the following

//Construction method
SparseTable(){
rowTotalNum = 500;
colTotalNum = 500;
for (int i=0; i<rowTotalNum; i++)
for (int i=0; i<colTotalNum; i++)
}
//Insert value value into a point (rowIndex, colIndex) of sparse table
void insert(int value ,int rowIndex, int colIndex){
if (rowIndex >= rowTotalNum || colIndex >= colTotalNum)
return ;
if(getValue(rowIndex, colIndex) != -1)
return ;
//Insert nodes into row list and column list respectively
row[rowIndex]->insertToRow(value, rowIndex, colIndex);
col[colIndex]->insertToCol(value, rowIndex, colIndex);
}

//Delete a node of a coordinate (rowIndex, colIndex)
void remove(int rowIndex, int colIndex){
if (rowIndex >= rowTotalNum || colIndex >= colTotalNum)
return ;
//Delete nodes on row and column lists
row[rowIndex]->deleteByRow(rowIndex, colIndex);
col[colIndex]->deleteByCol(rowIndex, colIndex);
}

//Get the value of the specified coordinate (rowIndex, colIndex)
//If there is no such node, return - 1
//There are two ways to do this, by column and by row
int getValue(int rowIndex, int colIndex){
if (rowIndex >= rowTotalNum || colIndex >= colTotalNum)
return -1;
//return col[colIndex]->getValueByCol(rowIndex, colIndex);
return row[rowIndex]->getValueByRow(rowIndex, colIndex);
}

//Print sparse table through row linked list
void printSelfByRow(){
cout<<"By row--------------------------"<<endl;
for (int i=0;i<=10;i++){
cout<<"("<<now->row<<", "<<now->col<<"): "<<now->value<<" ";
}
cout<<endl;
}
}

//Printing sparse tables with column linked lists
void printSelfByCol(){
cout<<"By col--------------------------"<<endl;
for (int i=0;i<=5;i++){
cout<<"("<<now->row<<", "<<now->col<<"): "<<now->value<<" ";
}
cout<<endl;
}

}

//Get column list of a column
return col[colIndex];
}
//Get row list of a row
return row[rowIndex];
}

};

//Test program
int main(){

SparseTable* st = new SparseTable();
st->insert(1,1,2);
st->insert(2,1,3);

st->insert(3,2,4);
st->insert(4,3,3);
st->insert(44,3,5);
st->insert(42,3,2);
st->insert(42,3,2);
st->printSelfByRow();
st->printSelfByCol();

st->remove(2,4);
st->remove(2,4);
st->printSelfByRow();
st->printSelfByCol();

st->remove(1,2);
st->printSelfByRow();
st->printSelfByCol();

cout<<"Get value: (3,5)"<<st->getValue(3,5)<<endl;
cout<<"Get value: (3,4)"<<st->getValue(3,4)<<endl;
cout<<"Get value: (3,2)"<<st->getValue(3,2)<<endl;
}

```  83 original articles published, 53 praised, 40000 visitors+

Posted by jswash on Mon, 27 Jan 2020 05:55:39 -0800