Data Structure and Algorithm Fundamentals (Wang Zhuo) (9): Application of Linear Tables (Ordered Table Merge) (Ordered, Repeatable)

Table of contents

Merge into a new whole: Merge of ordered lists (ordered, repeatable)

Linear table:

Process design for the specific implementation of this operation: (each module)

Module one:

Module two:

Module three:

Final revision polish:

Regarding linear tables: the merge (ordered, repeatable) operation of ordered tables is as follows:

linked list:

one,

two, 

three,

Final project:


PPT: Chapter 2 P176; 

 


Merge into a new whole: Merge of ordered lists (ordered, repeatable)

Linear table:

Process design for the specific implementation of this operation: (each module)

  1. Create an empty table C
  2. In turn, "extract" nodes with smaller element values ​​from A or B (middle) and insert them into the end of the C table until the

    A table becomes empty

  3. Continue to insert the remaining nodes of one of the tables A or B into the end of the C table


Module one:

For module one here, we need to:

For the entire learning process and problems of the operation of creating a new table to return the result of the merge of the two tables (the final merged table), see:

Data Structure and Algorithm Fundamentals (Wang Zhuo) (8) Attachment: Part 2 of the detailed explanation on the use of new;

In this program, we use the statement, namely:

    C.elem = new Elemtype[100]; 

Module two:

Among them, the process realization of module 2 is further subdivided into:

  1.  Extract the node with the smaller element value in the two tables
  2. Insert a node at the end of the C list
  3. Repeat steps "1" and "2" until one of the tables becomes empty

project1:

    //不用指针,直接硬钢判断语句
    int i = 0,//对应A表
        j = 0,//对应B表
        k = 0;//对应C表
    while (i < A.length || j < B.length)
    {
        if (A.elem[i] > B.elem[j])
        {
            C.elem[k] = B.elem[i];
            i++;
            k++;
        }

        if (A.elem[i] == B.elem[j])
        {
            C.elem[k] = A.elem[i];
            C.elem[++k] = B.elem[j];
            i++;
            j++;
            k++;
        }

        else//        if (A.elem[i] < B.elem[j])

        {
            C.elem[k] = A.elem[i];
            i++;
            k++;
        }
//当然,也可以先大于小于再等于

illustrate:

(1):

In module 2, the statement that the values ​​of the elements of the two nodes compared between the two tables are equal can also be written as:

        if (A.elem[i] == B.elem[j])
        {
            C.elem[k] = A.elem[i];
            C.elem[++k] = B.elem[j];
            i++;
            j++;
            k++;
        }

(2):

Need to pay attention (remember), originally (in the beginning), for the loop execution (of) judgment statement, we originally wanted to write it as

    while(A.elem[i] != 0 || B.elem[j] != 0)

However, the results show:

First of all, the first thing that is certain (conclusion) is:

Here, our program cannot complete the "!=" judgment in the statement

Here, if we want the program to successfully implement the judgment, we can have the following two solutions:

  • Hand roll a judgment definition expression about <Poly type> != <int type>
  • When the definition node is empty, the content of the empty node; that is: define such an empty node

Of course, if you really want to write it like this, you can do it, but it’s too troublesome, so we don’t choose this method here


Project 2: (Using the properties of linear table address linear array storage)

    //利用指针
    Poly* pa, * pb, * pc;
    pa = A.elem;
    pb = B.elem;
    pc = C.elem;

    //*pa = A.elem[0];
    //*pb = B.elem[0];

    while (pa <= &A.elem[A.length - 1] || pb < &B.elem[B.length - 1])
    {
        if (*pa > *pb)
        {
            *pc = *pb;
            pa++;
            pc++;
        }

        if (*pa == *pb)
        {
            *pc = *pa;
            *(++pc) = *pb;
            pa++;
            pb++;
            pc++;
        }

        else
        {
            *pc = *pa;
            pa++;
            pc++;
        }

Module three:

    if (A.length > B.length)
    {
        //while (i < A.length)  同理,后面不再赘述
        while (pa <= &A.elem[A.length - 1])    
        {
            *pc = *pa;
            pc++;
            pa++;
        }
    }
    else
    {
        while (pb <= &B.elem[B.length - 1])
        {
            *pc = *pb;
            pc++;
            pb++;
        }
    }

Final revision polish:

According to the standard answer in (reference) PPT (178), we found that there is still room for modification in the following places:


Module 1:

on the one hand:

We did not assign a value to the length element of the newly created C table

on the other hand:

The length of table C is the sum of the lengths of table A and table B

If it is still only fixed, it would be a bit inappropriate to open up a space with a fixed size of 100 like Table A and Table B:

  C.length = A.length + B.length; 
  C.elem = new Elemtype[C.length];

In addition, the qualification conditions we wrote here in module two:

    while (pa <= &A.elem[A.length - 1] || pb < &B.elem[B.length - 1])

written as:

    while (pa <= A.elem + A.length - 1 || pb < B.elem + B.length - 1)

The same reason (same); (the standard answer is written according to the latter, but I feel that there is nothing special about writing this way)


But another problem is serious:

In C++:

and:&&

or: ||

No:!

So it should be changed to:

    while (pa <= A.elem + A.length - 1 && pb < B.elem + B.length - 1)

 or:

    while (pa <= &A.elem[A.length - 1] && pb < &B.elem[B.length - 1])

in addition:

Regarding the loop body of this loop in module two, there is no big mistake in what I wrote

But it’s too cumbersome, and the standard answer is more concise and convenient

Of course, he is not as rigorous as I wrote: specifically write the operation process when the element values ​​​​of the two nodes are equal, which can reduce the number of cycles

But from the perspective of large time complexity, there is actually not much difference between n cycles and (n-5) cycles

So here we still choose the way of writing in the standard answer:

    while (pa <= &A.elem[A.length - 1] && pb < &B.elem[B.length - 1])
    {
        if (*pa < *pb)
            *pc++ = *pa++;
        else
            *pc++ = *pb++;
    }

This way of writing, that is:

First (to the last node in the C table (*pc)) assignment, and then self-increment; a statement to achieve


Finally, about module three:

In fact, we don’t need to set the judgment statement to see which table is longer in A or B.

Because in fact, even if we directly write two loop statements, it still does not affect the operation of the program.

Because the pointer of a table has reached the end node of the table, it naturally does not meet the loop judgment condition of the loop:

        while (pa <= &A.elem[A.length - 1])    

        while (pb <= &B.elem[B.length - 1])

In addition, the function body here can also be written in the form of " first assign a value to the last node (*pc) in the C table, and then increment; "

        while (pa <= &A.elem[A.length - 1])    
        {
            *pc++ = *pa++;
        }
        while (pb <= &B.elem[B.length - 1])
        {
            *pc++ = *pb++;
        }

To sum up:

Regarding linear tables: the merge (ordered, repeatable) operation of ordered tables is as follows:

int Merge(Sqlist A, Sqlist B, Sqlist& C)
{//合并; 融入; (使)结合; 并入; 相融;

    typedef Poly Elemtype;

    C.length = A.length + B.length;
    C.elem = new Elemtype[C.length];

    //利用指针
    Poly* pa, * pb, * pc;
    pa = A.elem;
    pb = B.elem;
    pc = C.elem;
    //*pa = A.elem[0];
    //*pb = B.elem[0];

    while (pa <= &A.elem[A.length - 1] && pb < &B.elem[B.length - 1])
    {
        if (*pa < *pb)
            *pc++ = *pa++;
        else
            *pc++ = *pb++;
    }
    //
    while (pa <= &A.elem[A.length - 1])
    {
        *pc++ = *pa++;
    }
    while (pb <= &B.elem[B.length - 1])
    {
        *pc++ = *pb++;
    }
    //
    return true;
}







linked list:

project 1:

int Merge(LinkList &A, LinkList& B, LinkList& C )
{
    //给指针赋初值
    LinkList
        pa = A->next,
        //注意:这里的指针指向的是AB表的首元结点而不是头结点
        pb = B->next,
        pc = C = A;
    //pc = A;
    //pc = &C = A;
 
    //比较并插入
    while(pa&&pb)
        //while (pa->next!=0&& pa->next != 0)
    {
        if (pb->data > pa->data)
        {
            pc->next = pa;
            pa = pa->next;
            //pc = pc->next;
        }
        else
        {
            pc->next = pb;
            pb = pb->next;
        }
    }
    //插入剩余段
    while(pa||pb)
    {
        pa ? pa : pb;
    }
    //返回操作成功信号
    return true;
}

in addition:

struct K
{
    float a;
    int b;
    string c;
    bool operator==(K& t)
    {
        return t.a == a && t.b == b;
        //&& t.c = c;
    }
    bool operator!=(K& t)
    {
        return t.a != a || t.b != b;
        //|| t.c = c;
    }
    bool operator>(K& t)
    {
        return t.a > a && t.b > b;
        //&& t.c = c;
    }
    bool operator<(K& t)
    {
        return t.a < a || t.b < b;
        //|| t.c = c;
    }
};

issues:

one,

about

        pc = C = A;
    //pc = A;
    //pc = &C = A;

(1): Continuous assignment expression? ? ?

        pc = C = A; is equivalent to: pc = (C = A); <C++ book P25>

(2): Why are the two styles (forms) in the comments not working?

1、

pc = A;

If we write it like this, we end up with:

We tinkered (written) the new table for a long time, and finally it was linked with table C, or our pointer to table C &C (the first address of C)

There is no connection (relationship), ie:

Creation is to create a new merged ordered list, but there is no way to go back and create a new lonely


2、

pc = &C = A;

result: 

Here we can actually relate to the problem in (1), where:

C represents the head pointer of the table C of Lnode type, which can also be regarded as a pointer of LinkList type

And after its address operation, &C represents the address of the pointer of this LinkList type

The address of this pointer is a fixed value (constant)

And a constant (a fixed value) must not be assigned by any other variable, so it is reasonable to report an error


Also, the same:

We don't think that this constant (unchangeable value) will be fine if it is on the leftmost side of the expression (the operation of the expression)

In addition to the fact that constants must be placed on the far left, we also need to pay attention to the unification of types:


Similarly, here, we make a systematic summary of the LinkList & A format that has been messing with us for a long time:

 What does &A stand for? ?

Lnode A: variable A of the linked list node type


Lnode &A: It still represents the variable A of the linked list node type, but (just) represents the value passing method of passing by reference


LinkList A: Points to the pointer variable A whose target object is the node type of the linked list

LinkList &A: still indicates that the target object is a pointer variable A of the linked list node type

It just
means that the address is conveyed (delivered) using the value-by-reference method


two, 

About loop judgment statement

    while(pa&&pb)
        //while (pa->next!=0&& pa->next != 0)

Why here it is only necessary to judge whether the value of the pointer is 0 to determine whether the program executes a loop?

How do you know that the addresses arranged by the program for the empty nodes that are not assigned later are all 0? ? ?


first:

We can't tell here (at least for now) that we can't tell the statement

        //while (pa->next!=0&& pa->next != 0)

Is it feasible, and the statement

    while(pa&&pb)

then simply means:

If both pa and pb are true, not false (empty), then the program will be executed, otherwise it will not be executed

There is no question about the relationship between 0 and false here. Of course, whether 0 can represent false is a question worth understanding (searching)


About the loop body:

The execution flow of the loop body:

Connect the nodes with smaller element values ​​to the end of table C (last, next)

Let the pointer of the C table (new table) point to the newly inserted node in the C table

(Because the subsequent nodes are all inserted after the newly inserted node)

Make the pointer to the list whose element was just extracted point to the next node in the list

In the process of writing the loop body, on the one hand:

After each node is inserted, the pointer to table A and table B is modified instead of the pointer to table C:

            pa = pa->next;
            //pc = pc->next;

the most important is:

We forgot the second step of the steps of the loop body we wrote here: pc = pa / pb;

And in fact, in the real operation, the second step cannot be written before the third step! ! !


three,

Don't forget that there is one more step before the final end:

    delete B;

Final project:

int Merge(LinkList &A, LinkList& B, LinkList& C)
{
    //给指针赋初值
    LinkList
        pa = A->next,
        //注意:这里的指针指向的是AB表的首元结点而不是头结点
        pb = B->next,
        pc = C = A;
 
    //比较并插入
    while(pa&&pb)

    {
        if (pb->data > pa->data)
        {
            pc->next = pa;
            pc = pa;
            pa = pa->next;
        }
        else
        {
            pc->next = pb;
            pc = pb;
            pb = pb->next;
        }
    }
    //插入剩余段
    while(pa||pb)
    {
        pa ? pa : pb;
    }

    delete B;
    //返回操作成功信号
    return true;
}

END

Guess you like

Origin blog.csdn.net/Zz_zzzzzzz__/article/details/128741026