• No results found

LINKED LISTS WITH POINTERS TO POINTERS

In document Fortran Array and Pointer Techniques (Page 123-128)

Maintaining a Large Ordered List

5.4 LINKED LISTS WITH POINTERS TO POINTERS

Some programming languages support pointers to pointers. Fortran does not permit a pointer whose target is a pointer, but it permits a pointer to a structure whose only component is a pointer. (Compare arrays of pointers, described in Chap. 2). Such a structure is here called a BOX: its type is BOX_Type and its only component is a node pointer named Next_NP, as shown in Fig. 5.3. A pointer to a BOX provides a Fortran substitute for a pointer to the node pointer inside the BOX. This permits iterative linked list search with insertion and deletion of nodes.

Here each linked list node has two components, one of which holds data, as before. The second component is now a BOX whose node pointer component Next_NP designates the remainder of the list:

The target of Next_NP is the linked list successor node, if there is one; otherwise, Next_NP is null. The root of the linked list is a BOX named Root; if the linked list is empty, the node pointer component of Root, designated as Root%Next_NP, is null.

type, private :: BOX_Type

type (Node_Type), pointer :: Next_NP => Null( ) end type BOX_Type

type, private :: Node_Type type (Info_Type) :: Info type (BOX_Type) :: BOX end type Node_Type

type (BOX_Type), pointer, private :: Trav_BP ! "traveling" BOX pointer type (BOX_Type), target, private, save :: Root

FIGURE 5.3. Fortran Pointer-to-Pointer technique

The traveling BOX pointer Trav_BP points to a BOX in the predecessor node; the node pointer in this BOX is Trav_BP % Next_NP, the forward pointer to the current node. If Trav_BP % Next_NP is null, no current node is the “target of the target” of Trav_BP. Otherwise (with Fortran’s automatic dereferencing), the components of the current node are referred to as Trav_BP % Next_NP % Info and Trav_BP % Next_NP % BOX. The latter is a BOX that contains a pointer to the remainder of the linked list; Trav_BP advances when this BOX is assigned as its new target: Trav_BP => Trav_BP % Next_NP % BOX.

5.4 LINKED LISTS WITH POINTERS TO POINTERS

Fig. 5.4 illustrates insertion of a new node ahead of the current node. The subroutine Insert_Target is called with argument Trav_BP%Next_NP to insert the new node as the target of the forward node pointer in the predecessor node. The only change from the version shown at the beginning of this chap-ter appears in the poinchap-ter assignment Temp_NP%BOX%Next_NP=>Arg_NP that links the current target of Arg_NP to the forward pointer Temp_NP%BOX%Next_NP in the new node.

subroutineInsert_Target(Arg_NP,Item) type(Node_Type),pointer::Arg_NP type(Info_Type),intent(in)::Item type(Node_Type),pointer::Temp_NP

! startsubroutineInsert_Target allocate(Temp_NP)

Temp_NP%Info=Item

Temp_NP%BOX%Next_NP=>Arg_NP Arg_NP=>Temp_NP

return

endsubroutineInsert_Target

Fig. 5.5 illustrates the procedure Delete_Target, which is called with the actual argument Trav_BP

%Next_NP, the forward node pointer in the predecessor node. The only change from the earlier version appears in the pointer assignment Arg_NP=>Arg_NP%BOX%Next_NP.

functionDelete_Target(Arg_NP)result(Item) type(Node_Type),pointer::Arg_NP

type(Info_Type)::Item

type(Node_Type),pointer::Temp_NP

! startfunctionDelete_Target

FIGURE 5.4. Inserting a new node ahead of the current node

115

5.4 LINKED LISTS WITH POINTERS TO POINTERS

Remainder of List Johnson

Kennedy

Lincoln Current Node Predecessor Node

Traveling Pointer Temporary Pointer

Root Pointer

Remainder of List

Johnson Kennedy Lincoln

Current Node Predecessor Node

Traveling Pointer Temporary Pointer

Root Pointer

FIGURE 5.5. Deleting the current node

Item=Arg_NP%Info

Arg_NP=>Arg_NP%BOX%Next_NP deallocate(Temp_NP)

return

endfunctionDelete_Target

The first step of the procedure Look_Up assigns Root (which has been declared in the module Linked_List_Ops) as the initial target of Trav_BP.

type(BOX_Type),target::Root :

subroutineLook_Up(Item)

type(Info_Type),intent(in)::Item

! startsubroutineLook_Up

Trav_BP=>Root !MakeRootthetargetofTrav_BP do

if(associated(Trav_BP%Next_NP))then

if(Item%Key==Trav_BP%Next_NP%Info%Key)then callModify_Target(Trav_BP%Next_NP)

elseif(Item%Key<Trav_BP%Next_NP%Info%Key)then callInsert_Target(Trav_BP%Next_NP,Item)

else

Trav_BP=>Trav_BP%Next_NP%BOX !Movetosuccessornode.

cycle !Keeplooking.

endif else

callInsert_Target(Trav_BP%Next_NP,Item) !Insertatend.

endif return enddo

endsubroutineLook_Up

This iterative procedure is equivalent to the earlier recursive version, modified by tail recursion removal and with the introduction of pointers to pointers.

Say It with Fortran

Example 15.

Shown here is a slightly modified version of the subroutine Look_Up for the Pointer to Pointer technique, along with a main program. The BOX named Root is declared in module. Procedures that operate at the target level are the same as with recursion.

! Example 15. Linked list with pointers to pointers.

module D15_M implicit none

public :: Look_Up, Print_List, Delete_List integer, parameter :: S_LEN = 20

type, public :: Info_Type

character (len = S_LEN) :: Key

integer, dimension(2) :: Data = (/ 0, 1 /) end type Info_Type

type, private :: BOX_Type

type (Node_Type), pointer :: Next_NP => Null( ) end type BOX_Type

type, private :: Node_Type type (Info_Type) :: Info type (BOX_Type) :: BOX end type Node_Type

type (BOX_Type), pointer, private :: Trav_BP !"traveling" BOX pointer type (BOX_Type), target, private, save :: Root

contains

subroutine Look_Up( Item )

type (Info_Type), intent(in) :: Item

! start subroutine Look_Up

Trav_BP => Root ! Make Root the target of Trav_BP The if constructs have been rearranged to agree with the recursive Fortran program shown earlier. Note that the enddo statement is never reached except from the cycle statement, which transfers control to the top of the do block.

do

if(associated(Trav_BP%Next_NP))then

if(Item%Key==Trav_BP%Next_NP%Info%Key)then callModify_Target(Trav_BP%Next_NP)

elseif(Item%Key<Trav_BP%Next_NP%Info%Key)then callInsert_Target(Trav_BP%Next_NP,Item)

else

Trav_BP=>Trav_BP%Next_NP%BOX !Movetosuccessornode.

cycle !Keeplooking.

endif else

callInsert_Target(Trav_BP%Next_NP,Item) !Insertatend.

endif return enddo contains

subroutineModify_Target(Arg_NP) :

endsubroutineModify_Target

117 subroutineInsert_Target(Arg_NP,Item)

:

endsubroutineInsert_Target endsubroutineLook_Up

subroutinePrint_List()

! startsubroutinePrint_List Trav_BP=>Root

dowhile(associated(Trav_BP%Next_NP)) callPrint_Target(Trav_BP)

Trav_BP=>Trav_BP%Next_NP%BOX !Advancetonextnode enddo

return contains

subroutinePrint_Target(Arg_BP) :

endsubroutinePrint_Target endsubroutinePrint_List subroutineDelete_List()

! startsubroutineDelete_List

dowhile(associated(Root%Next_NP))

print*,"Deleted:",Delete_Target(Root) enddo

return contains

functionDelete_Target(Arg_NP)result(Item) :

endfunctionDelete_Target endsubroutineDelete_List endmoduleD15_M

Section 5.4 Exercises

1. Write a recursive subroutine Print_List that prints information from the nodes of a linked list in reverse order: If the argument pointer is not null, call Print_List with the forward pointer (i.e., the remainder of the list) as its actual argument and then call Print_Target to print the current node.

Calling Print_List with the root node as the actual argument will print the entire list in reverse order.

2. Write a recursive subroutine Delete_List that deletes nodes from a linked list in reverse order: If the argument pointer is not null, call Delete_List with the forward pointer (i.e., the remainder of the list) as its actual argument and then call Delete_Target to delete the current node. (Print the Info component of each node as it is deleted.) Because the remainder of the list has already been deleted, the current node is the last node at the time it is deleted, and its deletion nullifies the argu-ment pointer. Calling Delete_List with the root node as the actual argument will delete the entire list in reverse order.

4. Implement the operation Look_Up with the data structure Item declared as a module variable;

modify the module procedures to inherit Item and modify the main program to import it.

5.4 LINKED LISTS WITH POINTERS TO POINTERS

5.5. APPLICATIONS WITH SEVERAL

In document Fortran Array and Pointer Techniques (Page 123-128)