The preceding section provides a brief overview and introduction of data structures and algorithms. In this article, we will introduce a typical data structure-linear structure.
What is a linear structure? A linear structure is the simplest, most basic, and most commonly used data structure. A linear table is an Abstract of a linear structure. A linear structure is characterized by a one-to-one linear relationship between data elements in the structure. This
A one-to-one relationship refers to the positional relationship between data elements, that is, (1) except for the data element at the first position, there is only one data element before the positions of other data elements. (2) except for the data element at the last position, there is only one element behind the positions of other data elements. That is to say, data elements are arranged one by one. Therefore, we can think of a linear structure as a data structure of a sequence of data elements.
A linear structure (List) is a finite sequence composed of n (n ≥ 0) data elements of the same type. Pay attention to two concepts for this definition: one is "finite", which means that the number of data elements in a linear table is limited, each data element in a linear table has its own Position ). This book does not discuss linear tables with an infinite number of data elements. Second, "same type" means that all data elements in a linear table belong to the same type. This is reflected in the commonly used data structures, such as arrays and generics, which are linear structures.
The relationship between them is: the formal definition of a linear table is: The linear table (List) is simplified to L, is a binary group, L = (D, R) where: D is a finite set of data elements. R is a finite set of relationships between data elements.
The basic operations for linear structures are as follows:
Public interface IListDS <T> {
Int GetLength (); // evaluate the length
Void Clear (); // Clear operation
Bool IsEmpty (); // determines whether the linear table is empty.
Void Append (T item); // additional operation
Void Insert (T item, int I); // Insert operation
T Delete (int I); // Delete operation
T GetElem (int I); // retrieves the table element.
Int Locate (T value); // search by value
}
Here why is IListDS and. Net comes with IList is different. Each method is described as follows:
1. Length: GetLength ()
Initial Condition: a linear table exists;
Operation Result: returns the number of all data elements in a linear table.
2. Clear ()
Initial Condition: a linear table has data elements;
Operation Result: all data elements are cleared from the linear table. The linear table is empty.
3. Determine whether the linear table is empty: IsEmpty ()
Initial Condition: a linear table exists;
Operation Result: If the linear table is empty, true is returned. Otherwise, false is returned.
4. Additional operation: Append (T item)
Initial Condition: The linear table exists and is not full;
Operation Result: add the new element with the value of item to the end of the table.
5. Insert operation: Insert (T item, int I)
Initial Condition: a linear table exists and the inserted position is correct () (1 ≤ I ≤ n + 1, n indicates the table length before insertion ).
Operation Result: Insert a new element with the item value at the position I of the linear table so that the original sequence is I, I + 1 ,..., The serial number of n data elements is changed to I + 1, I + 2 ,..., N + 1. The inserted Table length = the original table length + 1.
6. Delete operation: Delete (int I)
Initial Condition: The linear table exists and is not empty. The deletion location is correct (1 ≤ I ≤ n, and n indicates the table length before deletion ).
Operation Result: Delete the data element with the serial number I in the linear table and return the deleted data element. After deletion, set the original sequence to I + 1, I + 2 ,..., The serial number of n data elements is changed to I, I + 1 ,..., N-1. After deletion, the table length = the original table length-1.
7. Get table meta: GetElem (int I)
Initial Condition: The linear table exists and the position of the retrieved data element is correct (1 ≤ I ≤ n, and n is the table length of the linear table). Operation Result: the I-th Data Element in the linear table is returned.
8. Search by value: Locate (T value)
Initial Condition: a linear table exists.
Operation Result: the data element whose value is searched in a linear table. The result returns the sequence number of the data element whose value is value for the first time in a linear table. Otherwise, no data element with a value is found in the linear table. A special value is returned, indicating that the query failed.
First look at the simplest linear structure-sequence table
What is a sequence table and sequential storage of a linear structure refers to storing the data elements of a linear table in sequence using an address-contiguous space in the memory, the linearity stored in this way is called the Sequence List ).
Sequence Table Storage Structure
Assume that each data element in the sequence table occupies w storage units and the storage address of the I-th data element is Loc (ai), the following are available: Loc (ai) = Loc (a1) + (I-1) * w 1 ≤ I ≤ n in the Loc (a1) represents the storage address of the first data element A1, the Base Address of the sequence table ). here is an example. For example, when you go to the hotel, you know the baseline position of Room 101. If you want to go to Room 111, you know that the distance between each room is 5, there only needs to move forward 50 meters. The address operation of the sequence table is so simple.
The sequence table is inherited and linear, and its source code is like this.
Public class SeqList <T>: IListDS <T> {
Private int maxsize; // the maximum capacity of the sequential table.
Private T [] data; // array, used to store data elements in a sequence table, used to store the structure of a sequence table
Private int last; // indicates the position of the last element in the sequence table.
// Indexer
Public T this [int index]
{
Get
{
Return data [index];
}
Set
{
Data [index] = value;
}
}
// The location attribute of the last data element
Public int Last
{
Get
{
Return last;
}
}
// Capacity attribute
Public int Maxsize
{
Get
{
Return maxsize;
}
Set
{
Maxsize = value;
}
}
// The constructor initializes the function.
Public SeqList (int size)
{
Data = new T [size];
Maxsize = size;
Last =-1;
}
// Calculate the length of the sequence table
Public int GetLength ()
{
Return last + 1;
}
// Clear the sequence table
// Clear the data element in the sequence table to empty the sequence table. At this time, last equals to-1.
Public void Clear ()
{
Last =-1;
}
// Determine whether the sequence table is empty
// If the last value of the sequence table is-1, the sequence table is null and true is returned. Otherwise, false is returned.
Public bool IsEmpty ()
{
If (last =-1)
{
Return true;
}
Else
{
Return false;
}
}
// Determine whether the sequence table is full
// If the order table is full and last is equal to the maxsize-1, true is returned; otherwise, false is returned.
Public bool IsFull ()
{
If (last = maxsize-1)
{
Return true;
}
Else
{
Return false;
}
}
// When the sequence table is not full, add a new element at the end of the table and add the last element to the sequence table by 1.
// Add new elements at the end of the sequence table
Public void Append (T item)
{
If (IsFull ())
{
Console. WriteLine ("List is full ");
Return;
}
Data [++ last] = item;
}
// Insertion of an ordered table refers to inserting a new element with the item value at the position I of the ordered table. After insertion, the original table length is n (a1, a2 ,... , Ai-1, ai, ai + 1 ,... , An) into a table with a length of n + 1 (a1, a2 ,..., Ai-1, item, ai, ai + 1 ,..., An ). When the value range of I is 1 ≤ I ≤ n + 1, and I is n + 1, data elements are inserted at the end of the sequence table. To insert a data element in a sequence table, follow these steps:
Copy codeThe Code is as follows: // (1) check whether the sequence table is full and the inserted position is correct. If the table is full or the inserted position is incorrect, it cannot be inserted;
// (2) if the table is not full and the inserted position is correct ~ Ai moves backward in sequence to empty the new data element. Use loops in algorithms;
// (3) Insert the new data element to the null position I;
// (4) Modify last (equivalent to modifying the table length) so that it still points to the last data element of the ordered table.
// Insert a data element at the position of the I Data Element in the sequence table
Public void Insert (T item, int I)
{
If (IsFull ())
{
Console. WriteLine ("List is full ");
Return;
}
If (I <1 | I> last + 2)
{
Console. WriteLine ("Position is error! ");
Return;
}
If (I = last + 2)
{
Data [last + 1] = item;
}
Else
{
For (int j = last; j >=i-1; -- j)
{
Data [j + 1] = data [j];
}
Data [I-1] = item;
}
++ Last;
}
Algorithm time complexity analysis: insert operations on sequence tables. The time is mainly consumed by moving data. insert an element at position I, from ai to an, we need to move a position backward. We need to move n-I + 1 in total.
Elements, and the value range of I is 1 ≤ I ≤ n + 1. When I is equal to 1, the maximum number of elements to be moved is n; when I is n + 1, no elements need to be moved. If the probability of inserting at the position I is pi
The number of times the data element is moved to n/2. This note: on average, the insert operation on the sequence table requires moving half of the data elements in the table. Therefore, the time complexity of the insert operation is O (n ).
// The delete operation of an ordered table is to delete the I data elements in the table from the ordered table. After deletion, the table whose original table length is n (a1, a2 ,... , Ai-1, ai, ai + 1 ,... , An) change to a table whose length is n-1 (a1, a2 ,..., Ai-1, ai + 1 ,..., An ). If the value range of I is 1 ≤ I ≤ n, and I is n, the data elements at the end of the sequence table are deleted.
To delete a data element from an ordered table, follow these steps:
(1) Determine whether the sequence table is empty or the deleted location is correct, and whether the table is empty or the deleted location is incorrect.
It cannot be deleted;
(2) If the table is not empty and the deletion location is correct ~ An moves forward sequentially. In Algorithm
Implement with loops;
(3) Modify last (equivalent to modifying the table length) so that it still points to the last element of the ordered table.
Copy codeThe Code is as follows: // Delete the I data element of the sequence table
Public T Delete (int I)
{
T tmp = default (T );
If (IsEmpty ())
{
Console. WriteLine ("List is empty ");
Return tmp;
}
If (I <1 | I> last + 1)
{
Console. WriteLine ("Position is error! ");
Return tmp;
}
If (I = last + 1)
{
Tmp = data [last --];
}
Else
{
Tmp = data [I-1];
For (int j = I; j <= last; ++ j)
{
Data [j] = data [j + 1];
}
}
-- Last;
Return tmp;
}
Algorithm time complexity analysis: the delete operation on the sequence table is the same as the insert operation, and the time is mainly consumed by moving data. Delete an element at position I. From ai + 1 to an, move the element n-I forward, the value range of I is 1 ≤ I ≤ n. When I is equal to 1, the maximum number of elements to be moved is n-1. When I is n, no elements need to be moved. If the probability of deletion at the position I is pi, the average number of moving data elements is (n-1)/2. This indicates that the deletion operation on the sequence table requires moving half of the data elements in the table on average. Therefore, the time complexity of the deletion operation is O (n ).
// The table meta operation returns the I-th Data Element in the sequence table. The value range of I is 1 ≤ I ≤ last + 1. Because tables are randomly accessed, if the I value is correct, the time complexity of the table meta operation is O (1 ).
// Obtain the I-th data element of the sequence table
Public T GetElem (int I)
{
If (IsEmpty () | (I <1) | (I> last + 1 ))
{
Console. WriteLine ("List is empty or Position is error! ");
Return default (T );
}
Return data [I-1];
}
// Value-based lookup in an ordered table is used to find the data elements that meet the given values in the table.
The simplest way to complete this operation in an ordered table is to compare the operation with the given value from the first element, returns the sequence number of the data element that is equal to the given value for the first time in the sequence table, which is called a successful query. Otherwise, there is no data element that matches the given value in the sequence table, if a special value is returned, the search fails.
Copy codeThe Code is as follows: // search for the data element with the value in the sequence table
Public int Locate (T value)
{
If (IsEmpty ())
{
Console. WriteLine ("List is Empty! ");
Return-1;
}
Int I = 0;
For (I = 0; I <= last; ++ I)
{
If (value. Equals (data [I])
{
Break;
}
}
If (I> last)
{
Return-1;
}
Return I;
}
}
Algorithm time complexity analysis: the main operation of value-based search in the sequence table is comparison. The number of comparisons is related to the position of the given value in the table and the table length. When the given value is equal to the first data element, the number of comparisons is 1. When the given value is equal to the last element, the number of comparisons is n. Therefore, the average number of comparisons is (n + 1)/2, and the time complexity is O (n ).
For example, if the sequence table L is known, write an algorithm to put it upside down, that is, to implement the operation shown in 2.4, where (a) is before the inversion, (B) is after the inversion.
I am thinking about how to change the number in the middle. The source code is as follows:
Copy codeThe Code is as follows: public void ReversSeqList (SeqList <int> L)
{
Int tmp = 0;
Int len = L. GetLength ();
For (int I = 0; I <= len/2; ++ I)
{
Tmp = L [I];
L [I] = L [len-I];
L [len-I] = tmp;
}
}
This algorithm only performs sequential scanning of data elements in the sequence table, which completes inversion. Therefore, the time complexity is O (n ). The running effect is as follows:
For example, in terms of my development experience, in the Tetris project, many of my sequence structures are used, for example, during initialization.
Copy codeThe Code is as follows: // initialization shape set, which contains seven shapes.
_ Pieces = new List <PieceBase> {new I (), new L (), new I2 (), new L2 (), new N (), new N2 (), new O (), new T ()};
// Initialize the box container (fill the entire container with the Block object)
Container = new Block [_ rows, _ columns];
For (int I = 0; I <_ rows; I ++)
{
For (int j = 0; j <_ columns; j ++)
{
Var block = new Block ();
Block. Top = I * block. rectangle. ActualHeight;
Block. Left = j * block. rectangle. ActualWidth;
Block. Color = null;
Container [I, j] = block;
}
}
// Initialize the container of the next shape (fill it with Block objects)
NextContainer = new Block [4, 4];
For (int I = 0; I <4; I ++)
{
For (int j = 0; j <4; j ++)
{
Var block = new Block ();
Block. Top = I * block. rectangle. ActualHeight;
Block. Left = j * block. rectangle. ActualWidth;
Block. Color = null;
NextContainer [I, j] = block;
}
}
// Create a new shape
CreatePiece ();
// Present the currently created shape
AddPiece (0, 0 );
// Timer is used to regularly move down the shape
_ Timer = new DispatcherTimer ();
_ Timer. Interval = TimeSpan. FromMilliseconds (_ initSpeed );
_ Timer. Tick + = _ timer_Tick;
GameStatus = GameStatus. Ready;
Let's take a look at the Square container I used for initialization. This container is a two-dimensional array, which is an obvious sequence table. Assign values to the top position and left position for initialization. This is equivalent to the sequential table initialization operation. The complexity of this algorithm is O (n² ).