Linear Table - Sequential Table

Linear Table - Sequential Table

Let's go straight to the introduction.

Definition of Linear Table

A linear table is a finite sequence (officially defined) of data elements with the same characteristics. In fact, it is a collection of data elements with the same characteristics that can be called a class arranged in a single linear structure.

The number of elements contained in the sequence is called the length of a linear table (some may think this is nonsense, but if you've learned graphs and trees, you know why you need to mention this concept in your definition here).

Abstract Data Type Description for Linear Tables

It is important to understand some basic operations in linear tables:

InitList(&L):Initialize Linear Table,Construct an empty linear table L
DestroyList(&L):Destroy Linear Table,Release Linear Table L Occupied memory space
ListEmpty(L):Determining whether a linear table is empty,if L Empty table,Returns true,Otherwise return false
ListLength(L):Finding the Length of a Linear Table,Return L Number of elements in
DispList(L):Print Linear Table,When a linear table L Not null-time sequential display L Range of each node in(That is L Element values stored in each space)
GetElem(L,i,&e):Evaluating a data element value in a linear table,use e Return L pass the civil examinations i Value of elements
LocateElem(L,e):Find by element value,Return L The first range in the e Sequence number of equal elements,If such an element does not exist,Return value is 0
(Is to find the first and in a linear table e Sequence number of equal elements)
ListInsert(&L,i,e):Insert Data Element e,stay L Of i Insert a new element in
ListDelete(&L,i,&e):Delete data elements e,delete L Of i Elements,And e To return its value 

The teacher spent a lesson explaining the meaning of''referential transfer''. I don't understand the exact principle. I personally have been following the principle of using referential transfer in a function, where changes in this parameter are still valid outside the function.

(Actually, I've also seen this & the role of replication in dynamic programming to reduce the length of parameter names)

Sequence table

Sequential tables are short for the sequential storage structure of linear tables, that is, all elements in a linear table are stored in their logical order once in a continuous storage space starting from the specified storage location in computer memory.

In C/C++ languages, an array type is used to implement a sequential table, and the size of the array is recorded as MaxSize, which is generally defined as an integer constant (or macro).

#define MaxSize 50

In the book, a linear table is represented by a struct SqList, where the member variable data[MaxSize] is all the elements of the linear table, and the other member variable length represents the actual length of the linear table.

//data denotes the value of an element, length denotes the length of a sequence, and ElemType denotes the type of element stored 
struct SqList{ElemType data[MaxSize]; int length;};

Implementation of Basic Operation of Sequential Table

For convenience, the stored element type defaults to int.

Establish Sequence Table

This establishment is not an initialization, but rather a whole sequential table, which is equivalent to having an array of a and storing it as a sequential table structure:

//Establish Sequence Table
void CreateList(SqList*& L,ElemType a[],int n){
	L=(SqList*)malloc(sizeof(SqList));//Not enough light, not enough space for pointers
	//Does it make sense to use new here? Anyway, you're all C and C++ mixed code 
	for (int i=0;i<n;i++) L->data[i]=a[i]; L->length=n;//One-to-one assignment 
}

Initialize Linear Table

The difference between this operation and the above is equivalent to the difference between initialization and handling, which initializes an empty sequential table of length 0:

//Initialize Linear Table 
void InitList(SqList*& L){L=(SqList *)malloc(sizeof(SqList)); L->length=0;}

You don't have to put anything in, it's simple and without a head.

Destroy Linear Table

Notice that this is called destroy, not empty. Emptying a sequential table simply changes the length value to 0, and destroying frees up the memory occupied by the sequential table (a difference you can feel quite with a little experience):

//Destroy Linear Table 
void DestroyList(SqList *&L){free(L);}//Free (pointer), which represents the space to which the pointer is freed

Determining whether a linear table is empty

Is to determine if length is zero:

//Determining whether a linear table is empty
bool ListEmpty(SqList* L){return(L->length==0);}

Output Linear Table Length

Return length:

//Finding the Length of a Linear Table
int ListLength(SqList* L){return(L->length);} 

Output Linear Table

Cyclic printing according to length:

//Output (Print) Linear Table 
void DispList(SqList* L){
	for (int i=0;i<L->length;i++) printf("%d ",L->data[i]); printf("\n");
}

Evaluating a data element value in a linear table

Is to return the i-1 element (the array starts at 0), but in order to tightly encapsulate, we need to determine if i is legal (is there a case less than 0 or greater than length):

//Evaluating a data element value in a linear table
bool GetElem(SqList* L,int i,ElemType& e){
	if (i<1||i>L->length) return false;//First you need to decide if it is legal 
	e=L->data[i-1]; return true;
}

Find by element value

Find one element at a time, and if found, return the subscript + 1 (the array starts at 0), or 0 if not found:

//Find by element value
int LocateElem(SqList* L,ElemType e){int i=0;
	while (i<L->length&&L->data[i]!=e) i++;//Because you only need to find the first one, use the while loop to look backwards for elements equal to e 
	(i>=L->length)?return 0:return i+1;//The criteria here can also be written i==L->length
	//When i==L->length, all elements representing subscripts less than L->length have been traversed, no elements equal to e 
}

Insert Data Element

As with inserting and requiring element values for a location, it is also important to determine whether the value of i is legal:

//Insert Data Element
bool ListInsert(SqList*& L,int i,ElemType e){int j; i--;//Convert Bits to Subscripts
	if (i<0||i>L->length) return false;//Judging if the value of i is legal 
	for (j=L->length;j>i;j--) L->data[j]=L->data[j-1]; //Move data[i] and the following elements back one position
	L->data[i]=e;//Insert element e at an empty location 
	L->length++; return true;//Linear table length + 1, insert successful 
} 

Delete data elements

Insertion and deletion are essentially the same:

//Delete data elements
bool ListDelete(SqList*& L,int i,ElemType& e){int j; i--; //Convert Bits to Subscripts
	if (i<0||i>L->length) return false;//Judging if the value of i is legal
	e=L->data[i];//Store values that need to be deleted 
	for (j=i;j<L->length-1;j++)	L->data[j]=L->data[j+1];//Move the element after data[i] forward one position
	//Moving forward is like squeezing out the location of data[i]	
	L->length--; return true;//Linear table length-1, deleted successfully
}

The basic set of operations is as follows:

#define MaxSize 50
typedef int ElemType;//For convenience, the default data type stored in the sequential table is int 
//data denotes the value of an element, length denotes the length of a sequence, and ElemType denotes the type of element stored 
struct SqList{ElemType data[MaxSize]; int length;};
//Establish Sequence Table
void CreateList(SqList*& L,ElemType a[],int n){
	L=(SqList*)malloc(sizeof(SqList));//Not enough light, not enough space for pointers
	//Does it make sense to use new here? Anyway, you're all C and C++ mixed code 
	for (int i=0;i<n;i++) L->data[i]=a[i]; L->length=n;//One-to-one assignment 
}//Initialize Linear Table 
void InitList(SqList*& L){L=(SqList *)malloc(sizeof(SqList)); L->length=0;}
//Destroy Linear Table 
void DestroyList(SqList*& L){free(L);}//Free (pointer), which represents the space to which the pointer is freed
//Determining whether a linear table is empty
bool ListEmpty(SqList* L){return(L->length==0);} 
//Finding the Length of a Linear Table
int ListLength(SqList* L){return(L->length);}
//Output (Print) Linear Table 
void DispList(SqList* L){
	for (int i=0;i<L->length;i++) printf("%d ",L->data[i]); printf("\n");
}//Evaluating a data element value in a linear table
bool GetElem(SqList* L,int i,ElemType& e){
	if (i<1||i>L->length) return false;//First you need to decide if it is legal 
	e=L->data[i-1]; return true;
}//Find by element value
int LocateElem(SqList* L,ElemType e){int i=0;
	while (i<L->length&&L->data[i]!=e) i++;//Because you only need to find the first one, use the while loop to look backwards for elements equal to e 
	(i>=L->length)?return 0:return i+1;//The criteria here can also be written i==L->length
	//When i==L->length, all elements representing subscripts less than L->length have been traversed, no elements equal to e 
}//Insert Data Element
bool ListInsert(SqList*& L,int i,ElemType e){int j; i--;//Convert Bits to Subscripts
	if (i<0||i>L->length) return false;//Judging if the value of i is legal 
	for (j=L->length;j>i;j--) L->data[j]=L->data[j-1]; //Move data[i] and the following elements back one position
	L->data[i]=e;//Insert element e at an empty location 
	L->length++; return true;//Linear table length + 1, insert successful 
}//Delete data elements
bool ListDelete(SqList*& L,int i,ElemType& e){int j; i--; //Convert Bits to Subscripts
	if (i<0||i>L->length) return false;//Judging if the value of i is legal
	e=L->data[i];//Store values that need to be deleted 
	for (j=i;j<L->length-1;j++)	L->data[j]=L->data[j+1];//Move the element after data[i] forward one position
	//Moving forward is like squeezing out the location of data[i]	
	L->length--; return true;//Linear table length-1, deleted successfully
} 

Examples of applications

Example 2.3

Designs an algorithm to delete all elements in a linear table whose values are equal to x, requiring an O(n) time complexity.

Analysis: Since the time complexity is O(n), it is definitely not possible to delete more than once, so my first thought is to iterate through L and put all the elements that are not equal to x into L and store them again:

void delnode1(SqList*&L ,ElemType x){int len=0,i;//The number of elements whose len record value is not equal to x
	//In fact, len represents not only the length of the new table, but also the subscript that should be stored when traversing elements that are not equal to x 
	for (i=0;i<L->length;i++) if (L->data[i]!=x)
		{L->data[len]=L->data[i]; len++;}
	L->length=len;//The length of the new order table L is equal to len 
}

Another practice is also provided in the book: counting to the first element, the number of elements equal to x, k, represents the offset distance from the old table to the new table, not equal to the element of X (that is, the difference between the original subscript and the transferred subscript), code as follows:

void delnode2(SqList*& L,ElemType x){int k=0,i=0;//Number of elements whose k record value is equal to x
	while (i<L->length){
		if (L->data[i]==x)?k++:L->data[i-k]=L->data[i]; //Elements not equal to x move forward k positions
		i++;//That's all done. Isn't it good to use a for loop? 
	}L->length-=k; //The length of the new order table L needs to be subtracted from the number of elements equal to x 
}

Compare the two methods together:

void delnode1(SqList*&L ,ElemType x){int len=0,i;//The number of elements whose len record value is not equal to x
	//In fact, len represents not only the length of the new table, but also the subscript that should be stored when traversing elements that are not equal to x 
	for (i=0;i<L->length;i++) if (L->data[i]!=x)
		{L->data[len]=L->data[i]; len++;}
	L->length=len;//The length of the new order table L is equal to len 
}
void delnode2(SqList*& L,ElemType x){int k=0,i=0;//Number of elements whose k record value is equal to x
	while (i<L->length){
		if (L->data[i]==x)?k++:L->data[i-k]=L->data[i]; //Elements not equal to x move forward k positions
		i++;//That's all done. Isn't it good to use a for loop? 
	}L->length-=k; //The length of the new order table L needs to be subtracted from the number of elements equal to x 
}

Example 2.4

Design an algorithm that uses the first element as the dividing line, moves all elements less than or equal to it forward to the front of the datum, and all elements greater than it to the back of the datum.

Analysis: If you've seen me This article People will definitely be able to react to it the first time. This problem is actually a process of quick sorting. I understand the principle well when I explained it. Let's look directly at the code and comments here:

void move1(SqList*& L){	int i=0,j=L->length-1;//In fact, they are generally expressed in terms of l and r
//Because this problem is a process of cutting in fast row, l and r represent the left and right ends of the interval, respectively. 
	ElemType pivot=L->data[0];//Base on data[0]
	while (i<j){//Scan alternately from both ends of the interval to the middle until i=j
		while (i<j&&L->data[j]>pivot) j--;//Scan right to left to find an element less than or equal to pivot
		while (i<j&&L->data[i]<=pivot) i++;//Scan left to right to find an element larger than pivot
		if (i<j) swap(L->data[i],L->data[j]);//Swap the positions of two elements 
	}swap(L->data[0],L->data[i]);//Exchange L->data[0] with L->data[i]
}
void move2(SqList*& L){	int i=0,j=L->length-1; ElemType pivot=L->data[0];
	while (i<j){
		while (j>i&&L->data[j]>pivot) j--;//Scan from right to left to find a data[j] less than or equal to pivot
		L->data[i]=L->data[j];//Find such data[j] and put it in data[i]
		while (i<j&&L->data[i]<=pivot) i++;//Scan left to right to find a record greater than pivot data[i]
		L->data[j]=L->data[i];//Find such data[i] and put it in data[j]
		//In fact, there is no difference between what you do here and what you do above, it's an exchange
		//Only the first operation is to locate the two numbers and swap them
		//This is equivalent to an interchange operation with staggered coverage 
	}L->data[i]=pivot;//If you don't understand it, the back code is not impossible. 
}

Quick Sort:

void quick_sort(int*a,int l,int r){//l and r represent the endpoints on both sides of the current sort, respectively 
	if (l<r){ int i=l,j=r,pivot=a[l];//pivot represents the base of the current sorting selection, and here we pick the first element
		while (i<j){
			while (i<j&&a[j]>=pivot) j--;//Find the first number less than pivot from right to left
			if (i<j) {a[i]=a[j];i++;}//Replace an element by placing this number less than pivot in the left-hand sequence
			//This replaced element ensures that it appears in the sequence on the right side by replacing the pivot that was first selected
			//So instead of an element disappearing, you can think of it as swapping the positions of two numbers greater than pivot and less than pivot 
			while (i<j&&a[i]<pivot) i++;//Do the same from left to right 
			if (i<j) {a[j]=a[i];j--;} 
		}a[i]=pivot;//Last replacement adjusts pivot to relative middle position
		//After doing this, we split the sequence through pivot into two sequences smaller than pivot and larger than pivot.
		quick_sort(a,l,i-1); quick_sort(a,i+1,r);//Recursive solution 
	}
}

2.5 is the class of 2.4, so don't do it here. Let's have a good understanding of the 2.4 splitting interval.

Tags: data structure

Posted on Sat, 11 Sep 2021 18:54:38 -0400 by veronicabend