Data Structure Learning 1 -- sequence table (C language description)

Source: Internet
Author: User

I am mainly studying the data structure (C Language) by Yan Weimin. I learned the algorithms in the book based on my own needs and added some learning experience to the implementation of the Code. Now I will record the learning process for reference in the future. I learned a lot of things. These things I learned at that time don't need to be forgotten for a long time, and my own ideas are precious treasures. It's a pity to abandon them. So I can check them whenever I need to record them, so that you don't have to start looking for code from the beginning with another book.

A linear table is the most commonly used and simplest data structure. A linear table is a finite sequence of n data elements. The sequential representation of a linear structure refers to storing the data elements of a linear table at a time with a set of sequential storage units, the logical relationship between data elements in a linear table is expressed by the element "physically adjacent" in the computer.

The learning of data structures begins with the simplest Sequential Representation of the simplest linear table.

Related Concepts: direct precursor elements, direct post-drive elements, empty tables, and bits are not described here because they are simple.

As long as the starting position of the linear table is determined, any data element in the linear table can be randomly accessed. Therefore, the sequential storage structure of the linear table is a random access storage structure. Because the array type in the Advanced Programming Language (here mainly referred to as c) also has the feature of instant access, arrays are usually used to describe the sequential storage structure in the data structure.

The learning procedure is as follows: sequence table structure -- sequence table initialization -- insert element -- delete element -- Element comparison -- Comparison of Two sequence tables.

1. Sequence Table Construction

Before constructing the sequence table, perform the following macro definitions and replace variables to help you understand the code:

#define TRUE 1#define FALSE 0#define OK 1#define ok 1#define ERROR 0#define error 0#define INFEASIBLE -1#define LIST_INIT_SIZE 100;#define LISTINCREMENT 10;typedef int ElemType;typedef int Status;

Use a struct to construct an ordered table and define the address, length, and storage capacity of the ordered table. The Code is as follows:

Typedef struct {elemtype * ELEM; // defines the array pointer of the element type in the sequence table, pointing to the base address of the sequence table bucket int length; // The length of the sequence table (I .e. the number of elements) int listsize; // The storage capacity currently allocated to the sequence table} sqlist;

 

2. Sequence Table Initialization

Next, initialize the sequence table, assign a pre-defined array space to the sequence table, and set the length of the current sequence table to 0, if the number of elements is greater than the allocated storage capacity, the capacity will be expanded (the capacity will not be expanded during initialization, and the sequence table will be expanded as needed ). The Code is as follows:

Status initlist (sqlist * l) {(* l ). ELEM = (elemtype *) malloc (100 * sizeof (elemtype); // you cannot use list_init_size because 100 is required. is the same for the realloc function below? If (* l ). ELEM = NULL) {exit (overflow);} (* l ). length = 0; (* l ). listsize = list_init_size; Return OK ;}

Use of the malloc function:

Function prototype:Extern void * malloc (unsigned int num_bytes)

Function: Apply to the system to allocate a specified size of memory. The return type is void. Void * Indicates a pointer of unknown type. C, C ++ stipulates that the void * type can be forcibly converted to any other type of pointer

Header file: when using the malloc function in VC, add malloc. h or stdlib. h.

Return Value: if the allocation is successful, the pointer pointing to the allocated memory is returned. Otherwise, the NULL pointer is returned. When the memory is no longer used, use the free () function to release the memory block.

In the Code (* l ). ELEM = (elemtype *) malloc (100 * sizeof (elemtype); the return value type is forcibly converted to elemtype *, because the returned value points to the allocated memory pointer (that is, the ELEM element of the sequence table * l ). The allocated memory size is 100 elemtypes in bytes.

For ease of debugging, create an ordered table and initialize it. Specify a certain length and assign values to each element in the table. The Code is as follows:

Sqlist * L1 = new sqlist (); initlist (L1); // test the initlist function (* L1 ). length = 10; for (Int J = 0; j <(* L1 ). length; j ++) {(* L1 ). ELEM [J] = J ;}

Note: After the pointer variable is defined, you must initialize it. A pointer that does not point to any address space is very dangerous! The above defines a sqlist struct pointer variable and allocates memory space for it.

To facilitate testing and simplify the amount of code, write an output function for calling to output the elements in the sequence table L. The Code is as follows:

void Output_L(SqList *L){for(int i=0;i<(*L).length;i++)cout<<(*L).elem[i]<<" ";}

You can call the output_l function to view the output of the sequence table L1: output_l (L1); the result is as follows:

The initialized sequence table L1 will be used in a lot of tests later in this article.

 

3. Insert elements in the sequence table

Function: Add a new element E before position I of the sequence table.

Idea: add element e to position I, so the elements originally at position I will be moved to Position I + 1 and pushed backward in sequence. After the shift, the sequence table length is + 1. The key issue is how to move the data. If the data is first inserted into E and then moved, the value at the I position after the insertion is E, and the value at the I position is unknown, because the storage space is occupied by E, you need to use an address to save the value at the original position before moving. This is troublesome. We use high and low addresses to move to the low address. First, we pass the value of the last position (assumed as P) of the sequence table to (p + 1, in this way, the position P is empty, P-1 is put into P, and so on. Finally, the position I is empty, and E is put into it, this completes the insertion of the sequence table.

To insert an element, first determine whether the inserted position is correct, and then determine whether the storage space is sufficient. If not, the memory allocation will be increased.

Note: Here I use the insert pointer e value to the I position of the sequence table, because the listinsert function also uses some of the following functions, I have debugged many times during the learning process. Some function parameters use pointers, while some function parameters do not use pointers. They are prone to errors during function calls. Therefore, pointers are used here, to avoid various unmatched parameters during function calling, it is difficult to modify the parameters. The Code is as follows:

Status listinsert (sqlist (* l), int I, elemtype * E) {elemtype * newbase, * P, * q; if (I <1 | I> (* l ). length + 1) {return error;} If (* l ). length> = (* l ). listsize) {newbase = (elemtype *) realloc (* l ). ELEM, (* l ). listsize + 10) * sizeof (elemtype); // you cannot use listincrement. You must use 10. The following row can be used. Why? Is it related to the realloc function (* l ). ELEM = newbase; (* l ). listsize = (* l ). listsize + listincrement;} q = & (* l ). ELEM [I-1]); For (P = & (* l ). ELEM [(* l ). length-1]); P> = Q; p --) {* (p + 1) = * P;} * q = * E; (* l ). length ++; Return OK ;}

It should be noted that the cyclic termination condition in the for loop is.

Use of realloc functions:

Function prototype:Extern void * realloc (void * mem_address, unsigned int newsize)

It indicates that void * indicates the Data Type of the returned pointer and can be forcibly converted to another type (which is the same as malloc). The first parameter of the function indicates the pointer name to change the memory size, that is, the pointer pointing to the memory to be changed. The second parameter indicates the new size to be allocated. The new size must be greater than the original size. Otherwise, data will be lost.

Header file: # include <stdlib. h> Some compilers need # include <alloc. h>

Function: first allocates space according to the size specified by newsize, copies the original data from start to end to the newly allocated memory area, and then releases the memory area specified by the original mem_address, return the first address of the newly allocated memory area. That is, the address of the memory block is re-allocated.

Returned value: If the reallocation succeeds, the pointer pointing to the allocated memory is returned. Otherwise, the NULL pointer is returned.

Note: The data in the original memory remains unchanged. When the memory is no longer used, use the free () function to release the memory block.

The listinsert function is used to test the following code:

Elemtype Li1 = 8; elemtype * li2; li2 = & Li1; listinsert (L1, 5, li2); cout <"test the listinsert function:" <Endl; output_l (L1); cout <Endl;

The debugging result is as follows:

 

4. Deletion of elements in the sequence table

Function: stores the Element Parameter at position I of the sequence table in Pointer E.

Idea: After the element at position I is deleted, the position of all subsequent elements must be shifted one by one. In contrast to the method of moving an element after it is added, after the element is deleted, we move it from a low address to a high address. Because an element is deleted, you do not have to determine whether the storage space is sufficient. However, you must determine whether the deletion location is reliable. Do not forget that the length of the last sequence table must be-1.

The Code is as follows:

Status listdelete (sqlist * l, int I, elemtype * E) {elemtype * P, * q; if (I <0 | I> = (* l ). length) {return error;} q = & (* l ). ELEM [I-1]); // Q is the location of the deleted element * E = * q; P = & (* l ). ELEM [(* l ). length-1]); // P points to the address of the last element in the sequence table for (Q; q <p; q ++) {* q = * (q + 1);} (* l ). length --; Return OK ;}

It should be noted that the cyclic termination condition in the for loop is different from the element Insertion Algorithm.

Test the listdelete function. Assume that the element at the L1 position in the sequence table is deleted and the element is stored in Pointer variable E. The Code is as follows:

Elemtype * E = new elemtype (); cout <"test the listdelete function:" <Endl; listdelete (L1, 4, e); output_l (L1 ); cout <Endl; cout <"E =" <* E <Endl;

The debugging result is as follows:

 

5. Element comparison in the sequence table

Function: Find the position of the first element in the ordered linear table that matches the value of compare () in Pointer E. If no value exists, return 0.

First, define the compare () function. Assume that the relationship is equal. Use the Compare function. If the values of the two pointers are equal, true is returned, if they are not equal, false is returned. The Code is as follows:

Bool compare (elemtype * E1, elemtype * E2) // All parameters are represented by pointers, to avoid parameter mismatch during inter-function calls {If (* e1 = * E2) return true; else return false ;}

Based on this relationship, to find out the elements in the sequence table, the obvious idea is to compare the elements to see if the compare () relationship is satisfied. One thing to note here is the position of the element and the representation of the array element. The element at the position I is (* l). ELEM [I-1]. The Code is as follows:

Int locateelem (sqlist * l, elemtype * E) {int I = 1; // I is the position elemtype * P in the sequence table; // P points to the element P = (* l) whose order is I ). ELEM; // get the first element address of the array while (I <= (* l ). length &&(! Compare (p, E) {I ++; P ++;} if (I <= (* l ). length) return I; // return the position of the element that meets the condition ielse return 0 ;}

Test the locateelem function. The Code is as follows:

Elemtype le1 = 4; elemtype * le2; le2 = & le1; cout <"test the locateelem function:" <Endl; int A = locateelem (L1, le2 ); cout <le1 <"element location:" <A <Endl;

The debugging result is as follows:

 

6. operation between two sequence tables

Function: inserts data elements in a linear table LB but not in LA into the linear table la. The elements in LA are inserted sequentially, but not in any order.

Idea: this is a small synthesis of the sequence table application. First, we need to determine whether each element in the LB of the linear table exists in the linear table la. We need to use the locateelem function and insert the element, the listinsert function is required. Because these two functions are well understood before, it would be easier to complete this algorithm.

The algorithm involves retrieving elements and defines a function getelem () to store the I-th element in the linear table L into pointer E. The Code is as follows:

void GetElem(SqList *L,int i,ElemType *e){if(i>0&&i<=(*L).length)*e=(*L).elem[i-1];}

Using this function and the previous two functions to complete the algorithm is very simple. Put the Code directly, as shown below:

Void collect (sqlist * La, sqlist * lb) {elemtype * E = new elemtype (); // The local pointer variable is allocated with memory space, pay attention to releasing memory space int la_len = (* la) after use ). length; int lb_len = (* lb ). length; For (INT I = 1; I <= lb_len; I ++) {getelem (LB, I, e); If (! Locateelem (La, E) {listinsert (La, la_len + 1, e); // note that at this time, the length of La is not 1la_len ++ ;}} delete (E );}

Test the algorithm. During the test, initialize another sequence table L2. The Code is as follows:

Cout <"test the connect function:" <Endl; sqlist * L2 = new sqlist (); initlist (L2); // After the sqlist variable is defined and initialized, do not forget to use this function to construct an empty linear table (* l2) before assigning values ). length = 10; for (Int J = 0; j <(* l2 ). length; j ++) {(* l2 ). ELEM [J] = J * 2;} cout <"linear table L2:" <Endl; output_l (L2); cout <Endl; collect (L1, L2 ); cout <"linear table L1 after the connect function is executed:" <Endl; output_l (L1 );

The debugging result is as follows:

 

Note: The program should not forget to use the pointer variable allocated with memory space new to release memory space with Delete. If the sequence table is no longer used, the applied memory space will be free.

These are the operations of the sequence table. If you want to use other operations, read the sequence table. Next is the chained representation and implementation of linear tables. Come on!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.