home *** CD-ROM | disk | FTP | other *** search
- (* TBTree16 Copyright (c) 1988,1989 Dean H. Farwell II *)
-
- unit Sort;
-
- (*****************************************************************************)
- (* *)
- (* S O R T R O U T I N E S *)
- (* *)
- (*****************************************************************************)
-
-
- (* This unit contains the data types and routines required to sort logical
- record lists. It will handle logical record lists created from either
- fixed length (LOGICAL unit) or variable length (VLOGICAL unit) record data
- files. A logical record list can be sorted on any number of fields. This
- unit technically violates the object oriented design techniques used
- throughout TBTREE because it directly manipulates an object ( LrList)
- external to this unit. This is done to optimize performance. To alleviate
- this, I could combine this unit with the LRECLIST unit. I opted against
- this since sorting is considered by most people to be a separate type of
- operation than the operations performed by the LRECLIST unit. The decision
- really doesn't affect anything as far as the user is concerned.
-
- Sorting using this unit is generally straighforward. To sort a logical
- record list takes two steps. The first is to build a sort field list, a
- list containing information on each of the fields to sort on. The second
- step is to call SortList with the correct parameters. Once the sort is
- completed you should call DestroySortList which will return the space
- used to store the sort field list. This last step does not need done if
- you intend to sort on the same fields at a later time.
-
- Step 1 - Call AddFieldToSortList for each field to sort on. In other words
- if you are sorting on three fields, you must call AddFieldToSortList three
- times. When calling the routine you must supply a sort field variable (a
- pointer) which is equal to NIL for the first call to the routine. You must
- also supply the size of the field in bytes and the byte position of the
- field within the logical record and the ValueType of the field. Again, for
- the first call, when building a list, sPtr must be NIL. The
- AddFieldToSortList routine must be called once for each field. The field
- passed in the first call has the highest sort precedence. The field passed
- in as the next field will have the next highest precedence etc. The only
- tricky part is determining the byte position of a field within a logical
- record. Probably the only way to do it is manually determine how much room
- is taken be the preceding fields. An easy way to store it is to have a
- record which contains the position for each field. For example:
-
- MyRecord = record
- name : String[20];
- age : Byte;
- jobTitle : JobType; { assume it's an enumerated type }
- end;
-
- MyRecordPos = record
- namePos : Byte;
- agePos : Byte;
- jobTitlePos : Byte;
- end;
-
- var myPos : MyRecordPos;
-
- procedure SetPosMyRecord;
-
- begin
- myPos.namePos := 1;
- myPos.agePos := 22; { note it's not 21 since the previous field
- is 21 bytes (1 for the length) }
- myPos.jobTitlePos := 23;
- end;
-
- var sPtr : SortFieldList;
-
- procedure BuildMyList;
-
- begin { sort on age then name
- sPtr := NIL; { very important !! }
- AddFieldToSortList(sPtr,myPos.agePos,BYTEVALUE);
- AddFieldToSortList(sPtr,myPos.namePos,STRINGVALUE):
- end;
-
-
- This method will make it easier if you're ever change your logical record
- definitions.
-
- Step 2 - Now that you have built the list, simply call SortList. The call
- is simple. The list to sort, the file name of the data file and the sort
- field list are all passed in. Also, a boolean variable is passed in. If
- the sort was successful, TRUE will be returned in that variable. If there
- was not enough heap space available to perform the sort, FALSE is returned.
-
- Once the call is made the list will be sorted and returned. One thing
- is important to realize. Sorting takes time. Although the calls are
- simple to the user, there is a great deal of work going on behind the
- scenes. Sort times will vary from seconds to minutes depending on the size
- of the list and to a lesser extent the size of the logical records and the
- type of fields. In version 1.5 I made significant changes which speed up
- sorting by about a factor of 3. I have included an example program which
- can be used as desired.
-
- note - I used the QuickSort algorithm found in the book Data Structures and
- Algorithms by Aho, Hopcroft and Ullman. I took the liberty of making a few
- changes to speed them up for this particular application. *)
-
- (*\*)
- (* Version Information
-
- Version 1.1 - Not Applicable. This unit was introduced in version 1.2
-
- Version 1.2 - Added this entire unit.
-
- Version 1.3 - No Changes
-
- Version 1.4 - Added Numbers unit to uses clause
-
- - Deleted size parameter from the SortList routine
-
- Version 1.5 - Changed entire unit internally to significantly increase
- performance
-
- - Changed code internally to use Inc and Dec where practical
-
- - Changed the call to SortList. Now, a variable is set to TRUE
- if the sort was successful. If there was not enough heap
- space available, it is set to FALSE.
-
- Version 1.6 - Fixed error which occurred which would lead to an infinite
- loop when the heap became full while allocating heap space
- for the sort.
-
- - Changed unit internally to facilitate sorting variable length
- record files.
-
- - Fixed error which caused a sort field list to be modified
- after a sort is accomplished. Now, the sort field list is
- unmodified upon return (as advertised)
-
- - Fixed error which caused record numbers to be lost from a
- logical record list upon termination of the sort
-
- - Fixed internal error which occurred during allocation of
- memory required for sorting *)
-
- (*\*)
- (*////////////////////////// I N T E R F A C E //////////////////////////////*)
-
- interface
-
- uses
- Compare,
- FastMove,
- FileDecs,
- Files,
- Logical,
- LRecList,
- Numbers,
- Page,
- Vlogical;
-
- type
- SortFieldPosition = DataSizeRange; (* byte position of sort field
- within the data record *)
-
- SortFieldList = ^SortField; (* used to form a linked list containing info
- about sort fields *)
-
- SortField = record (* used to keep info about one
- sort field *)
- size : DataSizeRange; (* size of sort field in bytes *)
- dataPos : SortFieldPosition; (* byte position of sort field
- relative to the beginning of
- the data record *)
- sortPos : SortFieldPosition; (* byte position of sort field
- relative to the beginning of
- the sort record *)
- vType : ValueType; (* type of the field *)
- next : SortFieldList;
- end;
-
- (*\*)
- (* This routine will take a previously used list and delete all entries. sPtr
- will end up being NIL after the call. It is important to call this routine
- rather than just setting sPtr to NIL because this routine will return the
- heap space used by the list. *)
-
- procedure DestroySortList(var sPtr : SortFieldList);
-
-
- (* This routine will add one sort field to the end of a sort field list. The
- size of the field (in bytes), the byte position of the field within the
- data record and the type of the field must be supplied. The pointer to the
- sort field list must also be supplied. Remember, when this routine is
- called for the first field, sPtr must equal NIL!!! The list is kept in the
- order of entry. Therefore, the first entry should be the first field to
- sort on, the second field should be the next field to sort on if the first
- fields in two or more records contain the same value etc.
-
- Note : Two improtant notes are in order here. First, you must specify pos
- such that the entire field is part of the data record. In other words,
- make sure that you don't pass in pos = 11 when the data record is only 10
- bytes long. Likewise, if the field is 2 bytes long and the data record is
- 10 bytes long, pos must be 9 or less to make sense. Secondly, you must be
- extra careful when dealing with variable length record data files. The
- fields to sort on must still be in a fixed place in every record, or the
- sort will not function properly. To accommodate this, you should put the
- fixed parts of the record in the beginning and the variable length parts at
- the end. Then you can sort on the fixed length fields and possibly the
- first variable length field (since its position will be fixed). *)
-
- procedure AddFieldToSortList(var sPtr : SortFieldList;
- size : DataSizeRange;
- pos : SortFieldPosition;
- vType : ValueType);
-
- (*\*)
- (* This routine sorts a logical record list (lrLst) in ascending order using
- the sort field list passed in as a parameter. The file name for the data
- file must also be passed in. lrlst is passed in unsorted and is returned
- sorted in ascending order. If the caller wants to traverse the list in
- descending order, call this routine and traverse the resulting list in
- reverse order.
-
- note - prior to sorting, this routine checks the heap to see if there is
- sufficient heap space to perform the sort. The routine requires 2 blocks
- of heap memory each equal to the number of bytes required to store all of
- the sort fields together and one block equal to the logical record size of
- the data records in the data file (fName). There must be enough room on
- the heap to hold these blocks. It also needs enough space to copy the list
- held in sPtr. This working copy is required so that the list represented
- by sPtr will not be modified upon return. If there is not enough heap
- space the sort is terminated and success is returned with a value of FALSE.
- The list and the SortFiledList will be returned unchanged. If there is
- enough heap space, the list will be sorted and success will be returned
- equal to TRUE. Although, a sort will be successful if the minimum heap
- space is available, performance will be greatly increased if there is more
- room available on the heap. Try to make sure that there is about 40K bytes
- or so available. Large sort fields (strings) or a large number of sort
- fields will benefit from even more heap space. Once the sort is completed,
- any space used is returned to the available heap space. Therefore, it makes
- sense to leave as much heap space for the sort as you can. *)
-
- procedure SortList(var lrLst : LrList; (* list to sort *)
- fName : FnString; (* data file name *)
- sPtr : SortFieldList;
- var success : Boolean); (* list holding sort fields *)
-
-
- (*!*)
- (*\*)
- (*///////////////////// I M P L E M E N T A T I O N /////////////////////////*)
-
- implementation
-
- const
- MAXSORTINDEX = 500; (* number of cells in the SortPointerArray *)
-
- type
- SortIndexRange = 1 .. MAXSORTINDEX;
-
- HeapArrayPtr = ^HeapArray;
- HeapArray = Array[1 .. MAXDATASIZE] of Byte; (* can't use DataSizeRange
- because of zero
- subscript *)
-
- SortPointerRecord = record
- lrNum : LrNumber;
- heapPtr : HeapArrayPtr; (* pointer to the heap where
- sort fields are located *)
- end;
-
- SortPointerArray = Array [SortIndexRange] of SortPointerRecord;
-
-
- (* This routine will copy the sort field list sPtr to newSPtr. sPtr will not
- be affected. The routine will return TRUE if there was enough heap space
- to do the copy and FALSE otherwise. *)
-
- function CopySortList(sPtr : SortFieldList;
- var newSPtr : SortFieldList) : Boolean;
-
- var
- tempPtr1,
- tempPtr2 : SortFieldList;
-
- begin
- tempPtr1 := sPtr;
- tempPtr2 := NIL;
- while (tempPtr1 <> NIL) and
- (MaxAvail >= SizeOf(SortField)) do
- begin
- if tempPtr2= NIL then
- begin
- New(tempPtr2);
- newSPtr := tempPtr2;
- end
- else
- begin
- New(tempPtr2^.next);
- tempPtr2 := tempPtr2^.next;
- end;
- tempPtr2^ := tempPtr1^;
- tempPtr1 := tempPtr1^.next;
- end;
- CopySortList := (tempPtr1 = NIL);
- end; (* end of CopySortList routine *)
-
- (*\*)
- (* This routine will take a previously used list and delete all entries. sPtr
- will end up being NIL after the call. It is important to call this routine
- rather than just setting sPtr to NIL because this routine will return the
- heap space used by the list. *)
-
- procedure DestroySortList(var sPtr : SortFieldList);
-
- var
- tempPtr : SortFieldList;
-
- begin
- while sPtr <> NIL do
- begin
- tempPtr := sPtr^.next;
- Dispose(sPtr);
- sPtr := tempPtr;
- end;
- end; (* end of DestroySortList routine *)
-
- (*\*)
- (* This routine will add one sort field to the end of a sort field list. The
- size of the field (in bytes), the byte position of the field within the
- data record and the type of the field must be supplied. The pointer to the
- sort field list must also be supplied. Remember, when this routine is
- called for the first field, sPtr must equal NIL!!! The list is kept in the
- order of entry. Therefore, the first entry should be the first field to
- sort on, the second field should be the next field to sort on if the first
- fields in two or more records contain the same value etc.
-
- Note : Two improtant notes are in order here. First, you must specify pos
- such that the entire field is part of the data record. In other words,
- make sure that you don't pass in pos = 11 when the data record is only 10
- bytes long. Likewise, if the field is 2 bytes long and the data record is
- 10 bytes long, pos must be 9 or less to make sense. Secondly, you must be
- extra careful when dealing with variable length record data files. The
- fields to sort on must still be in a fixed place in every record, or the
- sort will not function properly. To accommodate this, you should put the
- fixed parts of the record in the beginning and the variable length parts at
- the end. Then you can sort on the fixed length fields and possibly the
- first variable length field (since its position will be fixed). *)
-
- procedure AddFieldToSortList(var sPtr : SortFieldList;
- size : DataSizeRange;
- pos : SortFieldPosition;
- vType : ValueType);
-
- var
- tempPtr : SortFieldList;
-
- begin
- if sPtr = NIL then
- begin
- New(sPtr);
- tempPtr := sPtr;
- end
- else
- begin
- tempPtr := sPtr;
- while tempPtr^.next <> NIL do
- begin
- tempPtr := tempPtr^.next;
- end;
- New(tempPtr^.next);
- tempPtr := tempPtr^.next;
- end;
- tempPtr^.size := size;
- tempPtr^.dataPos := pos;
- tempPtr^.sortPos := 0;
- tempPtr^.vType := vType;
- tempPtr^.next := NIL;
- end; (* end of AddFieldToSortList routine *)
-
-
- (*\*)
- (* This routine sorts a logical record list (lrLst) in ascending order using
- the sort field list passed in as a parameter. The file name for the data
- file must also be passed in. lrlst is passed in unsorted and is returned
- sorted in ascending order. If the caller wants to traverse the list in
- descending order, call this routine and traverse the resulting list in
- reverse order.
-
- note - prior to sorting, this routine checks the heap to see if there is
- sufficient heap space to perform the sort. The routine requires 2 blocks
- of heap memory each equal to the number of bytes required to store all of
- the sort fields together and one block equal to the logical record size of
- the data records in the data file (fName). There must be enough room on
- the heap to hold these blocks. It also needs enough space to copy the list
- held in sPtr. This working copy is required so that the list represented
- by sPtr will not be modified upon return. If there is not enough heap
- space the sort is terminated and success is returned with a value of FALSE.
- The list and the SortFiledList will be returned unchanged. If there is
- enough heap space, the list will be sorted and success will be returned
- equal to TRUE. Although, a sort will be successful if the minimum heap
- space is available, performance will be greatly increased if there is more
- room available on the heap. Try to make sure that there is about 40K bytes
- or so available. Large sort fields (strings) or a large number of sort
- fields will benefit from even more heap space. Once the sort is completed,
- any space used is returned to the available heap space. Therefore, it makes
- sense to leave as much heap space for the sort as you can. *)
-
- procedure SortList(var lrLst : LrList; (* list to sort *)
- fName : FnString; (* data file name *)
- sPtr : SortFieldList;
- var success : Boolean); (* list holding sort fields *)
-
- var
- newSPtr : SortFieldList; (* holds temporary copy of newSPtr *)
- newLrLst : LrList;
- sPtrArr : SortPointerArray;
- sRecSize : DataSizeRange; (* size of record created from all sort fields *)
- lRecSize : DataSizeRange; (* logical record size *)
- recs,
- recsInArray : SortIndexRange;
- recsLeft : LrNumber;
- extraHeapPtr : HeapArrayPtr; (* used to point to heap location which will
- be used for two purposes at separate
- times as follows:
- current record in the lrList being merged
- copy of the pivot sort record *)
-
- logicalHeapPtr : HeapArrayPtr; (* used to initially hold the logical
- record when it is read in *)
- dummyLrNum : LrNumber;
-
-
- (*\*)
- (* This routine will determine the logical record size needed to hold the
- varialble length data file logical records. It will dtermine what the
- minimum needed is. *)
-
- function CalculateDataRecordSize : DataSizeRange;
-
- var
- tempPtr : SortFieldList;
- recSize,
- lastByte : DataSizeRange;
-
- begin
- recSize := 0;
- tempPtr := newSPtr;
- while tempPtr <> nil do
- begin
- lastByte := (tempPtr^.dataPos - 1) + tempPtr^.size;
- if recSize < lastByte then
- begin
- recSize := lastByte;
- end;
- tempPtr := tempPtr^.next;
- end;
- CalculateDataRecordSize := recSize;
- end; (* end of CalcualteDataRecordSize roautine *)
-
-
- (* This routine will calculate the total of the size of all the sort
- fields. It will also update the sort list to show the byte position
- within the sort record for each field. *)
-
- function GetSortRecordSize : DataSizeRange;
-
- var
- tempPtr : SortFieldList;
- recSize : DataSizeRange;
-
- begin
- recSize := 0;
- tempPtr := newSPtr;
- while tempPtr <> NIL do
- begin
- tempPtr^.sortPos := recSize + 1;
- Inc(recSize,tempPtr^.size);
- tempPtr := tempPtr^.next;
- end;
- GetSortRecordSize := recSize;
- end; (* end of GetSortRecordSize routine *)
-
- (*\*)
- (* This routine will allocate, on the heap, the three distinct blocks of
- memory required to perform a sort. *)
-
- function AllocateMinimumSortSpace : Boolean;
-
- begin
- if MaxAvail >= sRecSize then
- begin
- GetMem(extraHeapPtr,sRecSize);
- end
- else
- begin
- AllocateMinimumSortSpace := FALSE;
- Exit;
- end;
- if MaxAvail >= sRecSize then
- begin
- GetMem(sPtrArr[1].heapPtr,sRecSize);
- end
- else
- begin
- FreeMem(extraHeapPtr,sRecSize);
- AllocateMinimumSortSpace := FALSE;
- Exit;
- end;
- if MaxAvail >= lRecSize then
- begin
- GetMem(logicalHeapPtr,lRecSize);
- end
- else
- begin
- FreeMem(extraHeapPtr,sRecSize);
- FreeMem(sPtrArr[1].heapPtr,sRecSize);
- AllocateMinimumSortSpace := FALSE;
- Exit;
- end;
- AllocateMinimumSortSpace := TRUE;
- end; (* end of AllocateMinimumSortSpace routine *)
-
- (*\*)
- (* This routine will allocate the space required for as many sort records
- (records made up of sort fields only) as will fit on the heap (up to
- MAXSORTINDEX). This routine assumes that AllocateMinimumSortSpace has
- been called and the space for the first entry (idx = 1) has already
- been allocated. It will return the total number of records allocated,
- including the first entry. *)
-
- function AllocateSortSpace : SortIndexRange;
-
- var
- idx : SortIndexRange;
- done : Boolean;
-
- begin
- idx := 1;
- done := FALSE;
- while (not done) and (idx < MAXSORTINDEX) do
- begin
- if MaxAvail >= sRecSize then
- begin
- Inc(idx);
- GetMem(sPtrArr[idx].heapPtr,sRecSize);
- end
- else
- begin
- done := TRUE;
- end;
- end;
- AllocateSortSpace := idx;
- end; (* end of AllocateSortSpace routine *)
-
- (*\*)
- (* This routine will retrieve one logical record and build the sort record
- from it. *)
-
- procedure GetOneSortRecord(lrNum : LrNumber;
- heapPtr : HeapArrayPtr);
-
- var
- sortPos : SortFieldPosition;
- tempPtr : SortFieldList;
-
- begin
- if FetchFileType(fName) = DATA then
- begin
- GetALogicalRecord(fName,lrNum,logicalHeapPtr^);
- end
- else
- begin
- VLRGetPartialLogicalRecord(fName,lrNum,
- logicalHeapPtr^,lRecSize);
- end;
- sortPos := 1;
- tempPtr := newSPtr;
- while TRUE do
- begin (* somewhat strange loop structure required
- to keep sortPos within range *)
- FastMover(logicalHeapPtr^[tempPtr^.dataPos],
- heapPtr^[sortPos],
- tempPtr^.size);
- if tempPtr^.next = NIL then
- begin
- Exit; (* only way out of loop *)
- end;
- Inc(sortPos,tempPtr^.size);
- tempPtr := tempPtr^.next;
- end;
- end; (* end of GetOneSortRecord routine *)
-
- (*\*)
- (* This routine will get the number of records specified (n) and will
- build the sort records on the heap. It will make the appropriate
- entries in the SortPointerArray. It will retrieve logical record
- numbers from the logical record list starting at the present position.
- The cursor will be advanced as the records are retrieved. The routine
- must not be called if the cursor is not positioned properly.
-
- One note!!! - this routine always gets (n) records. The caller must
- ensure that there are n records available *)
-
- procedure GetSortRecords(var lrLst : LrList;
- n : SortIndexRange);
-
- var
- idx : SortIndexRange;
- lrNum : LrNumber;
-
- begin
- lrNum := GetCurrLr(lrLst);
- for idx := 1 to n do
- begin
- sPtrArr[idx].lrNum := lrNum;
- GetOneSortRecord(lrNum,sPtrArr[idx].heapPtr);
- lrNum := GetNextlr(lrLst);
- end;
- end; (* end of GetSortRecords routine *)
-
- (*\*)
- (* This routine will compare logical record stored at the location
- specified by heapPtr1 with the logical record stored at the location
- specified by heapPtr2. The routine will return LESSTHAN if the first
- record is less than the second record for the sort fields in sPtr. It
- will return EQUALTO if the records are equal for those sort fields. It
- will return GREATERTHAN if the first record is greater than the second
- record for those sort fields. *)
-
- function CompareRecords(heapPtr1 : HeapArrayPtr;
- heapPtr2 : HeapArrayPtr) : Comparison;
-
- var
- tempPtr : SortFieldList;
- done : Boolean;
- result : Comparison;
-
- begin
- tempPtr := newSPtr;
- done := FALSE;
- while not done do
- begin
- result := CompareValues(heapPtr1^[tempPtr^.sortPos],
- heapPtr2^[tempPtr^.sortPos],
- tempPtr^.vType);
- case result of
- LESSTHAN :
- begin
- done := TRUE;
- end;
- GREATERTHAN :
- begin
- done := TRUE;
- end;
- EQUALTO :
- begin
- tempPtr := tempPtr^.next;
- done := (tempPtr = NIL);
- end;
- end; (* end of case statement *)
- end;
- CompareRecords := result;
- end; (* end of CompareRecords routine *)
-
-
- (*\*)
- (* This routine sorts the SortPointerArray in ascending order *)
-
- procedure SortRecords(n : SortIndexRange);
-
- type
-
- ModifiedSortIndexRange = 0 .. 501; (* needed for the quicksort
- routines
- should really be
- MAXSORTINDEX + 1 *)
-
- (* This routine swaps two values in the sPtrArr *)
-
- procedure Swap(idx1 : SortIndexRange;
- idx2 : SortIndexRange);
-
- var
- temp : SortPointerRecord;
-
- begin
- temp := sPtrArr[idx1];
- sPtrArr[idx1] := sPtrArr[idx2];
- sPtrArr[idx2] := temp;
- end; (* end of Swap routine *)
-
- (*\*)
- (* This routine will return the logical record number for the record which
- is the pivot record. *)
-
- function FindPivot(idx1 : SortIndexRange;
- idx2 : SortIndexRange) : ModifiedSortIndexRange;
-
- var
- idx3 : ModifiedSortIndexRange;
- mid : SortIndexRange;
-
- begin
- mid := (idx1 + idx2) Div 2; (* used to speed up sorts in the case
- where the records are almost
- already sorted *)
- Swap(idx2,mid);
- for idx3 := idx1 + 1 to idx2 do
- begin (* try to find record not equal to the first one *)
- case CompareRecords(sPtrArr[idx3].heapPtr,
- sPtrArr[idx1].heapPtr) of
- GREATERTHAN :
- begin
- FindPivot := idx3;
- Exit;
- end;
- LESSTHAN :
- begin
- FindPivot := idx1;
- Exit;
- end;
- EQUALTO : ;
- end; (* end of case statement *)
- end;
- FindPivot := 0; (* different keys not found *)
- end; (* end of FindPivot routine *)
-
- (*\*)
- (* This routine will partition the sPtrArr[idx1] .. sPtrArr[idx2] into
- two arrays so that sort records less than the sort record at
- sPtrArr[pivotIdx] are located prior to pivotIdx in the array and
- records greater and equal to are located after pivotIdx. This
- routine returns the index where the pivot record resides. *)
-
- function Partition(idx1 : SortIndexRange; (* must be passed by value *)
- idx2 : ModifiedSortIndexRange;
- (* must be passed by value *)
- pivotIdx : LrNumber) : SortIndexRange;
-
- begin
- FastMover(sPtrArr[pivotIdx].heapPtr^,extraHeapPtr^,sRecSize);
- repeat
- begin
- Swap(idx1,idx2);
- while CompareRecords(sPtrArr[idx1].heapPtr,
- extraHeapPtr) = LESSTHAN do
- begin
- Inc(idx1);
- end;
- while CompareRecords(sPtrArr[idx2].heapPtr,
- extraHeapPtr) <> LESSTHAN do
- begin
- Dec(idx2);
- end;
- end;
- until idx1 > idx2;
- Partition := idx1;
- end; (* end of Partition routine *)
-
-
- (* This routine will recursively sort the records in sPtrArr. *)
-
- procedure QuickSort(idx1 : SortIndexRange;
- idx2 : SortIndexRange);
-
- var
- idx3 : SortIndexRange;
- pivotIdx : ModifiedSortIndexRange;
-
- begin
- pivotIdx := FindPivot(idx1,idx2);
- if pivotIdx <> 0 then
- begin
- idx3 := Partition(idx1,idx2,pivotIdx);
- QuickSort(idx1,idx3-1);
- QuickSort(idx3,idx2);
- end;
- end; (* end of QuickSort routine *)
-
-
- begin (* main block of SortRecords routine *)
- QuickSort(1,n);
- end; (* end of SortRecords routine *)
-
- (*\*)
- (* This routine will perform a merge sort and merge the contents of the
- SortPointerArray with the contents of the new logical record list and
- leave the contents in the logical record list. *)
-
- procedure SortMergeLists(n : SortIndexRange;
- var newLrLst : LrList);
-
- var
- tempLrLst : LrList;
- lrNum : LrNumber;
- idx : SortIndexRange;
- done : Boolean;
-
- begin
- CreateLrList(tempLrLst);
- lrNum := GetFirstLr(newLrLst);
- for idx := 1 to n do
- begin
- done := FALSE;
- while (lrNum <> 0) and (not done) do
- begin
- GetOneSortRecord(lrNum,extraHeapPtr);
- if CompareRecords(sPtrArr[idx].heapPtr,extraHeapPtr) =
- LESSTHAN then
- begin
- done := TRUE;
- end
- else
- begin
- AddToLrList(lrNum,tempLrLst);
- lrNum := GetNextlr(newLrLst);
- end;
- end;
- AddToLrList(sPtrArr[idx].lrNum,tempLrLst);
- end;
- while lrNum <> 0 do
- begin
- GetOneSortRecord(lrNum,extraHeapPtr);
- AddToLrList(lrNum,tempLrLst);
- lrNum := GetNextlr(newLrLst);
- end;
- DestroyLrList(newLrLst);
- newLrLst := tempLrLst;
- end; (* end of SortMergeLists routine *)
-
-
- (* This routine will free up the heap space used for sorting, including
- the space used for the merge sort record and the temporary logical
- record. However, it will not free up the space used by the temporary
- sort list. *)
-
- procedure ReleaseSortRecords;
-
- var
- idx : SortIndexRange;
-
- begin
- for idx := recsInArray downto 1 do
- begin
- FreeMem(sPtrArr[idx].heapPtr,sRecSize);
- end;
- FreeMem(extraHeapPtr,sRecSize);
- FreeMem(logicalHeapPtr,lRecSize);
- end; (* end of ReleaseSortRecords routine *)
-
- (*\*)
- begin
- success := CopySortList(sPtr,newSPtr);
- if success then
- begin
- sRecSize := GetSortRecordSize;
- if FetchFileType(fName) = DATA then
- begin
- lRecSize := GetDataRecordSize(fName);
- end
- else
- begin
- lrecSize := CalculateDataRecordSize;
- end;
- success := AllocateMinimumSortSpace;
- if success then
- begin
- recsInArray := AllocateSortSpace;
- recsLeft := GetCountLr(lrLst);
- CreateLrList(newLrLst);
- dummyLrNum := GetFirstLr(lrLst); (* set the cursor in the lrlist
- list to the front of the list*)
- while recsLeft > 0 do
- begin
- if recsLeft <= recsInArray then
- begin
- recs := recsLeft;
- end
- else
- begin
- recs := recsInArray;
- end;
- Dec(recsLeft,recs);
- GetSortRecords(lrLst,recs);
- SortRecords(recs);
- SortMergeLists(recs,newLrLst);
- end;
- ReleaseSortRecords;
- DestroyLrList(lrLst);
- lrLst := newlrLst; (* newly sorted list to return *)
- end;
- end;
- DestroySortList(newSPtr); (* whether or not the sort was successful,
- this step needs to be accomplished *)
-
- end; (* end of SortList routine *)
-
-
- end. (* end of Sort Unit *)