I slept over the answer to question Quicksort drama and wanted to recode it from scratch, implementing your tip with the call-by-reference var. And again: I cannot find any failure I made again. I compare the code to your program one by one and I cannot find the problem. The following code produces an Exception (External:SIGSEV at address 11602) during compilation/run
program quicksort;
var
iArray : array[0..8] of integer;
procedure fillArray(var iArray : array of integer);
begin;
iArray[0] := 3;
iArray[1] := 1;
iArray[2] := 8;
iArray[3] := 4;
iArray[4] := 9;
iArray[5] := 0;
iArray[6] := 8;
iArray[7] := 2;
iArray[8] := 5;
end;
procedure writeArray(iArray : array of integer);
var i:integer;
begin
for i:=low(iArray) to high(iArray) do begin
write(iArray[i]);
end;
writeln('');
end;
procedure quickSort(var iArray : array of integer; links : integer; rechts:integer);
var
l,r,pivot, temp: integer;
begin
if (rechts > links) then begin
l := links;
r := rechts;
pivot := iArray[(rechts+links) div 2];
while (l<r) do begin
while (iArray[l] < pivot) do l:=l+1;
while (iArray[r] > pivot) do r:=r-1;
if (l<=r) then begin
temp := iArray[l];
iArray[l] := iArray[r];
iArray[r] := temp;
end;
end;
if (links < r) then quickSort(iArray, links, r);
if (l < rechts) then quickSort(iArray, l, rechts);
end;
end;
begin
fillArray(iArray);
quickSort(iArray,low(iArray),high(iArray));
writeArray(iArray);
end.
The block of code that swaps, also needs to increment l and decrement r once the swap is complete:
if (l <= r) then
begin
temp := iArray[l];
iArray[l] := iArray[r];
iArray[r] := temp;
inc(l); // <-- this was missing
dec(r); // <-- as was this
end;
The complete program, with some other minor tidy ups:
program quicksort24340509;
var
iArray: array [0 .. 8] of integer;
Procedure fillArray(var iArray: array of integer);
begin;
iArray[0] := 3;
iArray[1] := 1;
iArray[2] := 8;
iArray[3] := 4;
iArray[4] := 9;
iArray[5] := 0;
iArray[6] := 8;
iArray[7] := 2;
iArray[8] := 5;
end;
Procedure writeArray(const iArray: array of integer);
var
i: integer;
begin
for i := low(iArray) to high(iArray) do
begin
write(iArray[i], ' ');
end;
writeln;
end;
Procedure quickSort(var iArray: array of integer; links, rechts: integer);
var
l, r, pivot, temp: integer;
begin
if (rechts > links) then
begin
l := links;
r := rechts;
pivot := iArray[(rechts + links) div 2];
while l < r do
begin
while iArray[l] < pivot do inc(l);
while iArray[r] > pivot do dec(r);
if l <= r then
begin
temp := iArray[l];
iArray[l] := iArray[r];
iArray[r] := temp;
inc(l);
dec(r);
end;
end;
if links < r then
quickSort(iArray, links, r);
if l < rechts then
quickSort(iArray, l, rechts);
end;
end;
begin
fillArray(iArray);
quickSort(iArray, low(iArray), high(iArray));
writeArray(iArray);
readln;
end.
Output
0 1 2 3 4 5 8 8 9
The reason that your version fails, without the missing lines, is that the recursive calls to quickSort operate on the wrong ranges.
For example, Given your input of
3 1 8 4 9 0 8 2 5
the partitioning step pivots on 9 and results in
3 1 8 4 5 0 8 2 9
Now, the recursive step should be to sort all the values to the left of the pivot, and all the values to the right. And we leave the pivot alone because partitioning ensured that it is in its final position.
There are no values to the right of the pivot so we should be making a recursive call for the range 0 to 7. But if you inspect what happens with your code you will find that it does not. Instead it makes a recursive call for the range 0 to 8. That in itself is a little benign, but once the ranges become small, at the stopping condition, it's different. Try asking your program to sort these values:
1 2
The code pivots on 1. At the end of partitioning we have:
links = 0
rechts = 1
l = 0
r = 0
So we recursively call quickSort passing l and rechts as the ranges. But that's exactly the same call as we initially made. And that therefore leads to a stack overflow.
So the point is that we must make sure that when we partition on a pivot, we exclude that pivot from all future recursive calls to quickSort. If we don't do that we don't sub-divide the problem, and the recursion does not terminate.
Related
How do I determine which value occurs the most after I filled the array with 100 random values which are between 1 and 11?
Here is a sample code:
procedure TForm1.Button1Click(Sender: TObject);
function Calculate: Integer;
var
Numbers: array [1..100] of Byte;
Counts: array [1..11] of Byte;
I: Byte;
begin
// Fill the array with random numbers
for I := Low(Numbers) to High(Numbers) do
Numbers[I] := Random(11) + 1;
// Count the occurencies
ZeroMemory(#Counts, SizeOf(Counts));
for I := Low(Numbers) to High(Numbers) do
Inc(Counts[Numbers[I]]);
// Identify the maximum
Result := Low(Counts);
for I := Low(Counts) + 1 to High(Counts) do
if Counts[I] > Counts[Result] then
Result := I;
end;
begin
ShowMessage(Calculate.ToString);
end;
It is a simple question [...]
Yes
but I can't seem to find any straight answers online.
You shouldn't be searching for solutions on-line; instead, you should start to think about how to design an algorithm able to solve the problem. For this, you may need pen and paper.
First, we need some data to work with:
const
ListLength = 100;
MinValue = 1;
MaxValue = 11;
function MakeRandomList: TArray<Integer>;
begin
SetLength(Result, ListLength);
for var i := 0 to High(Result) do
Result[i] := MinValue + Random(MaxValue - MinValue + 1);
end;
The MakeRandomList function creates a dynamic array of integers. The array contains ListLength = 100 integers ranging from MinValue = 1 to MaxValue = 11, as desired.
Now, given such a list of integers,
var L := MakeRandomList;
how do we find the most frequent value?
Well, if we were to solve this problem without a computer, using only pen and paper, we would probably count the number of times each distinct value (1, 2, ..., 11) occurs in the list, no?
Then we would only need to find the value with the greatest frequency.
For instance, given the data
2, 5, 1, 10, 1, 5, 2, 7, 8, 5
we would count to find the frequencies
X Freq
2 2
5 3
1 2
10 1
7 1
8 1
Then we read the table from the top line to the bottom line to find the row with the greatest frequency, constantly keeping track of the current winner.
Now that we know how to solve the problem, it is trivial to write a piece of code that performs this algorithm:
procedure FindMostFrequentValue(const AList: TArray<Integer>);
type
TValueAndFreq = record
Value: Integer;
Freq: Integer;
end;
var
Frequencies: TArray<TValueAndFreq>;
begin
if Length(AList) = 0 then
raise Exception.Create('List is empty.');
SetLength(Frequencies, MaxValue - MinValue + 1);
// Step 0: Label the frequency list items
for var i := 0 to High(Frequencies) do
Frequencies[i].Value := i + MinValue;
// Step 1: Obtain the frequencies
for var i := 0 to High(AList) do
begin
if not InRange(AList[i], MinValue, MaxValue) then
raise Exception.CreateFmt('Value out of range: %d', [AList[i]]);
Inc(Frequencies[AList[i] - MinValue].Freq);
end;
// Step 2: Find the winner
var Winner: TValueAndFreq;
Winner.Value := 0;
Winner.Freq := 0;
for var i := 0 to High(Frequencies) do
if Frequencies[i].Freq > Winner.Freq then
Winner := Frequencies[i];
ShowMessageFmt('The most frequent value is %d with a count of %d.',
[Winner.Value, Winner.Freq]);
end;
Delphi has a TDictionary class, which you can use to implement a frequency map, eg:
uses
..., System.Generics.Collections;
function MostFrequent(Arr: array of Integer) : Integer;
var
Frequencies: TDictionary<Integer, Integer>;
I, Freq, MaxFreq: Integer;
Elem: TPair<Integer, Integer>;
begin
Frequencies := TDictionary<Integer, Integer>.Create;
// Fill the dictionary with numbers
for I := Low(Arr) to High(Arr) do begin
if not Frequencies.TryGetValue(Arr[I], Freq) then Freq := 0;
Frequencies.AddOrSetValue(Arr[I], Freq + 1);
end;
// Identify the maximum
Result := 0;
MaxFreq := 0;
for Elem in Frequencies do begin
if Elem.Value > MaxFreq then begin
MaxFreq := Elem.Value;
Result := Elem.Key;
end;
end;
Frequencies.Free;
end;
var
Numbers: array [1..100] of Integer;
I: Integer;
begin
// Fill the array with random numbers
for I := Low(Numbers) to High(Numbers) do
Numbers[I] := Random(11) + 1;
// Identify the maximum
ShowMessage(IntToStr(MostFrequent(Numbers)));
end;
I am also still learning and therefore feel that the way I approached this problem might be a little closer to the way would have done:
procedure TForm1.GetMostOccuring;
var
arrNumbers : array[1..100] of Integer;
iNumberWithMost : Integer;
iNewAmount, iMostAmount : Integer;
I, J : Integer;
begin
for I := 1 to 100 do
arrNumbers[I] := Random(10) + 1;
iMostAmount := 0;
for I := 1 to 10 do
begin
iNewAmount := 0;
for J := 1 to 100 do
if I = arrNumbers[J] then
inc(iNewAmount);
if iNewAmount > iMostAmount then
begin
iMostAmount := iNewAmount;
iNumberWithMost := I;
end;
end;
ShowMessage(IntToStr(iNumberWithMost));
end;
I hope this is not completely useless.
It is just a simple answer to a simple question.
I am building a stringlist from an ADO query, in the query it is much faster to return sorted results and then add them in order. this gives me an already sorted list and then calling either Sort or setting sorted true costs me time as the Quicksort algorithm does not preform well on an already sorted list. Is there some way to set the TStringList to use the Binary search without running the sort?
before you ask I don't have access to the CustomSort attribute.
I am not sure I understand what you are worried about, assuming the desired sort order of the StringList is the same as the ORDER BY of the AdoQuery.
Surely the thing to do is to set Sorted on your StringList to True while it is still empty and then insert the rows from the AdoQuery. That way, when the StringList is about to Add an entry, it will search for it using IndexOf, which will in turn use Find, which does a binary search, to check for duplicates. But using Add in this way does not involve a quicksort because the StringList is already treating itself as sorted.
In view of your comments and your own answer I ran the program below through the Line Timer profiler in NexusDB's Quality Suite. The result is that although there are detectable differences in execution speed using a binary search versus TStringList.IndexOf, they are nothing to do with the use (or not) of TStringList's QuickSort. Further, the difference is explicable by a subtle difference between how the binary search I used and the one in TStringList.Find work - see Update #2 below.
The program generates 200k 100-character strings and then inserts them into a StringList. The StringList is generated in two ways, first with Sorted set to True before any strings are added and then with Sorted set to True only after the strings have been added. StringList.IndexOf and your BinSearch is then used to look up each of the strings which has been added. The results are as follows:
Line Total Time Source
80 procedure Test;
119 0.000549 begin
120 2922.105618 StringList := GetList(True);
121 2877.101652 TestIndexOf;
122 1062.461975 TestBinSearch;
123 29.299069 StringList.Free;
124
125 2970.756283 StringList := GetList(False);
126 2943.510851 TestIndexOf;
127 1044.146265 TestBinSearch;
128 31.440766 StringList.Free;
129 end;
130
131 begin
132 Test;
133 end.
The problem I encountered is that your BinSearch never actually returns 1 and the number of failures is equal to the number of strings searched for. If you can fix this, I'll be happy to re-do the test.
program SortedStringList2;
[...]
const
Rows = 200000;
StrLen = 100;
function ZeroPad(Number : Integer; Len : Integer) : String;
begin
Result := IntToStr(Number);
if Length(Result) < Len then
Result := StringOfChar('0', Len - Length(Result)) + Result;
end;
function GetList(SortWhenEmpty : Boolean) : TStringList;
var
i : Integer;
begin
Result := TStringList.Create;
if SortWhenEmpty then
Result.Sorted := True;
for i := 1 to Rows do
Result.Add(ZeroPad(i, StrLen));
if not SortWhenEmpty then
Result.Sorted := True;
end;
Function BinSearch(slList: TStringList; sToFind : String) : integer;
var
i, j, k : integer;
begin
try
i := slList.Count div 2;
k := i;
if i = 0 then
begin
Result := -1;
// SpendLog('BinSearch List Empty, Exiting...');
exit;
end;
while slList.Strings[i] <> sToFind do
begin
if CompareText(slList.Strings[i], sToFind) < 0 then
begin
j := i;
k := k div 2;
i := i + k;
if j=i then
break;
end else
if CompareText(slList.Strings[i], sToFind) > 0 then
begin
j := i;
k := k div 2;
i := i - k;
if j=i then
break;
end else
break;
end;
if slList.Strings[i] = sToFind then
result := i
else
Result := -1;
except
//SpendLog('<BinSearch> Exception: ' + ExceptionMessage + ' At Line: ' + Analysis.LastSourcePos);
end;
end;
procedure Test;
var
i : Integer;
StringList : TStringList;
procedure TestIndexOf;
var
i : Integer;
Index : Integer;
Failures : Integer;
S : String;
begin
Failures := 0;
for i := 1 to Rows do begin
S := ZeroPad(i, StrLen);
Index := StringList.IndexOf(S);
if Index < 0 then
Inc(Failures);
end;
Assert(Failures = 0);
end;
procedure TestBinSearch;
var
i : Integer;
Index : Integer;
Failures : Integer;
S : String;
begin
Failures := 0;
for i := 1 to Rows do begin
S := ZeroPad(i, StrLen);
Index := BinSearch(StringList, S);
if Index < 0 then
Inc(Failures);
end;
//Assert(Failures = 0);
end;
begin
StringList := GetList(True);
TestIndexOf;
TestBinSearch;
StringList.Free;
StringList := GetList(False);
TestIndexOf;
TestBinSearch;
StringList.Free;
end;
begin
Test;
end.
Update I wrote my own implementation of the search algorithm in the Wikipedia article https://en.wikipedia.org/wiki/Binary_search_algorithm as follows:
function BinSearch(slList: TStringList; sToFind : String) : integer;
var
L, R, m : integer;
begin
L := 0;
R := slList.Count - 1;
if R < L then begin
Result := -1;
exit;
end;
m := (L + R) div 2;
while slList.Strings[m] <> sToFind do begin
m := (L + R) div 2;
if CompareText(slList.Strings[m], sToFind) < 0 then
L := m + 1
else
if CompareText(slList.Strings[m], sToFind) > 0 then
R := m - 1;
if L > R then
break;
end;
if slList.Strings[m] = sToFind then
Result := m
else
Result := -1;
end;
This seems to work correctly, and re-profiling the test app using this gave these results:
Line Total Time Source
113 procedure Test;
153 0.000490 begin
154 3020.588894 StringList := GetList(True);
155 2892.860499 TestIndexOf;
156 1143.722379 TestBinSearch;
157 29.612898 StringList.Free;
158
159 2991.241659 StringList := GetList(False);
160 2934.778847 TestIndexOf;
161 1113.911083 TestBinSearch;
162 30.069241 StringList.Free;
On that showing, a binary search clearly outperforms TStringList.IndexOf and contrary to my expectations it makes no real difference whether TStringList.Sorted is set to True before or after the strings are added.
Update#2 it turns out that the reason BinSearch is faster than TStringList.IndexOf is purely because BinSearch uses CompareText whereas TStringList.IndexOf uses AnsiCompareText (via .Find). If I change BinSearch to use AnsiCompareText, it becomes 1.6 times slower than TStringList.IndexOf!
I was about to suggest using an interposer class to directly change the FSorted field without calling its setter method which as a side effect calls the Sort method. But looking at the implementation of TStringList in Delphi 2007, I found that Find will always do a binary search without checking the Sorted property. This will, of course fail, if the list items aren't sorted, but in your case they are. So, as long as you remember to call Find rather than IndexOf, you don't need to do anything.
in the end I just hacked up a binary search to check the stringlist like an array:
Function BinSearch(slList: TStringList; sToFind : String) : integer;
var
i, j, k : integer;
begin
try
try
i := slList.Count div 2;
k := i;
if i = 0 then
begin
Result := -1;
SpendLog('BinSearch List Empty, Exiting...');
exit;
end;
while slList.Strings[i] <> sToFind do
begin
if CompareText(slList.Strings[i], sToFind) < 0 then
begin
j := i;
k := k div 2;
i := i + k;
if j=i then
break;
end else
if CompareText(slList.Strings[i], sToFind) > 0 then
begin
j := i;
k := k div 2;
i := i - k;
if j=i then
break;
end else
break;
end;
if slList.Strings[i] = sToFind then
result := i
else
Result := -1;
except
SpendLog('<BinSearch> Exception: ' + ExceptionMessage + ' At Line: ' + Analysis.LastSourcePos);
end;
finally
end;
end;
I'll clean this up later if needed.
I'm build an application that reducing the pixels width.
When I'm pressing the button of that application two or three times, Message will appear and say stack overflow.
Here's the Message :
Error Line on my application
Here's my code :
procedure TForm1.cariThin();
var
baris_gbr, kolom_gbr, x, y, a, b, i, j, p1, p2, n : integer;
imgval : array [0..500,0..500] of integer;
mark : array [0..500,0..500] of integer;
nb : array [1..9] of integer;
hasdelete: boolean;
R, G, BL, AB : integer;
begin
Image3.Width := Image1.Width;
Image3.Height := Image1.Height;
baris_gbr := Image1.Picture.Height;
kolom_gbr := Image1.Picture.Width;
For kolom_gbr:= 0 To image1.Width - 1 Do
Begin
For baris_gbr:= 0 To image1.Height - 1 Do
Begin
R:= GetRValue(image1.Canvas.Pixels[kolom_gbr, baris_gbr]);
G:= GetGValue(image1.Canvas.Pixels[kolom_gbr, baris_gbr]);
BL:= GetBValue(image1.Canvas.Pixels[kolom_gbr, baris_gbr]);
AB:= (R + G + BL) Div 3;
if (AB > 200) then
begin
Image1.Canvas.Pixels[kolom_gbr, baris_gbr] := rgb(255,255,255);
end
else
begin
Image1.Canvas.Pixels[kolom_gbr, baris_gbr] := rgb(0,0,0);
end;
End;
End;
for y := 0 to baris_gbr-1 do
begin
for x := 0 to kolom_gbr-1 do
begin
if (Image1.canvas.pixels[x,y] = clBlack) then
begin
imgval[x,y] := 1;
end
else
begin
imgval[x,y] := 0;
end;
end;
end;
hasdelete := True;
while (hasdelete) do
begin
hasdelete := False;
for y := 0 to baris_gbr-1 do
begin
for x := 0 to kolom_gbr-1 do
begin
if (imgval[x,y] = 1) then
begin
for n:=1 to 8 do
begin
nb[n] := 0;
nb[1] := imgval[x,y];
nb[2] := imgval[x,y-1];
nb[3] := imgval[x+1,y-1];
nb[4] := imgval[x+1,y];
nb[5] := imgval[x+1,y+1];
nb[6] := imgval[x,y+1];
nb[7] := imgval[x-1,y+1];
nb[8] := imgval[x-1,y];
nb[9] := imgval[x-1,y-1];
a := 0;
end;
for i:= 2 to 8 do
begin
if ((nb[i] = 0) AND (nb[i+1] = 1)) then
begin
inc(a);
end;
end;
if ((nb[9] = 0) AND (nb[2] = 1)) then
begin
inc(a);
end;
b := nb[2] + nb[3] + nb[4] + nb[5] + nb[6] + nb[7] + nb[8] + nb[9];
p1 := nb[2] * nb[4] * nb[6];
p2 := nb[4] * nb[6] * nb[8];
if ((a = 1) AND ((b>=2) AND (b <= 6)) AND (p1 = 0) AND (p2 = 0)) then
begin
mark[x,y] := 0;
hasdelete := true;
end
else
begin
mark[x,y] := 1;
end
end
else
begin
mark[x,y] := 0;
end;
end;
end;
for y:=0 to baris_gbr-1 do
begin
for x:=0 to kolom_gbr-1 do
begin
imgval[x,y] := mark[x,y];
end;
end;
end;
end;
Why my application keep says overflow? is there any solution to fix it? or can we can exception handler? thanks
EDIT
Now my pplication says access violation.
It raised error in this line : nb[7] := imgval[x-1,y+1];
why it exactly happened?
var
imgval : array [0..500,0..500] of integer;
mark : array [0..500,0..500] of integer;
These variables are located on the stack and are huge. They have size 501*501*4 = 1,004,004. The default stack size is 1MB. These large arrays are the reason for your stack overflow.
You will need to use dynamically allocated arrays instead. Or avoid the need to store 2D arrays that contain information for each pixel and instead process the image in smaller sub-blocks. I've no idea whether or not that is possible because I've no idea what the code is trying to do. That's for you to work out.
Of course, one advantage of using dynamically allocated arrays is that you don't need to run the gauntlet of a buffer overrun, as you currently do. If either dimension of the image exceeds 501 then you have overrun the buffer. I do hope that you have enabled range checking in the compiler options.
for y := 0 to baris_gbr-1 do
and
for x := 0 to kolom_gbr-1 do
cannot be correct. The baris_gbr and kolom_gbr variables are not initialised since they were most recently used as loop variables. So, as well as turning on range checking, you'll want to turn on hints and warnings, and then heed them.
Say I have the data
1,2,3,4,5,6
I want to sort this data so that it outputs
6 1 5 2 4 3
This way, numbers are matched so that low numbers pair with high numbers
Would i use a merge sort to sort it in numerical order, then split the list and match them according to this conditions?
I'm trying to sort real number data in a string grid which is read from a data file; I have a working program that sorts these data in numerical order but I'm not sure how to code it so that it sorts in terms of high,low,high,low
This is the code for my grid sorting
procedure TForm1.SortGrid(Grid: TStringGrid; const SortCol: Integer;
//sorting the string grid
const datatype: Integer; const ascending: boolean);
var
i: Integer;
tempgrid: TStringGrid;
list: array of Integer;
begin
tempgrid := TStringGrid.create(self);
with tempgrid do
begin
rowcount := Grid.rowcount;
ColCount := Grid.ColCount;
fixedrows := Grid.fixedrows;
end;
with Grid do
begin
setlength(list, rowcount - fixedrows);
for i := fixedrows to rowcount - 1 do
begin
list[i - fixedrows] := i;
tempgrid.rows[i].assign(Grid.rows[i]);
end;
Mergesort(Grid, list, SortCol + 1, datatype, ascending);
for i := 0 to rowcount - fixedrows - 1 do
begin
rows[i + fixedrows].assign(tempgrid.rows[list[i]])
end;
row := fixedrows;
end;
tempgrid.free;
setlength(list, 0);
end;
First, sort the numbers in descending order by using any algorithm you want (I used bubble sort in example)
Then, if you have n elements in array:
set a counter going from 1 to (n div 2)
take last element and store it in temporary variable (tmp)
shift all elements by one place to the right, starting from (counter - 1) * 2 + 1. This would overwrite last element, but you have it stored in tmp var
set array[(counter - 1) * 2 + 1] element to tmp
end counter
This way you would effectively take last element from array and insert it at 1, 3, 5... position, until you insert last half of array elements.
Sample code:
procedure Sort(var AArray: array of Double);
var
C1, C2: Integer;
tmp : Double;
pivot : Integer;
begin
for C1 := Low(AArray) to High(AArray) - 1 do
for C2 := C1 + 1 to High(AArray) do
if AArray[C1] < AArray[C2] then
begin
tmp := AArray[C1];
AArray[C1] := AArray[C2];
AArray[C2] := tmp;
end;
pivot := Length(AArray) div 2;
for C1 := 1 to pivot do
begin
tmp := AArray[High(AArray)];
for C2 := High(AArray) downto (C1 - 1) * 2 + 1 do
AArray[C2] := AArray[C2 - 1];
AArray[(C1 - 1) * 2 + 1] := tmp;
end;
end;
From sample data you provided above, I am assuming that the input array is presorted.
[Note that I don't have a compiler at hand, so you'll have to run it and see that it works --minor fiddling might be needed.]
procedure SerratedSort(var AArray: array of Double);
var
Length1: Integer;
Index1: Integer;
Temp1: Double;
begin
Length1 := Length(AArray);
Index1 := 0;
while Index1 < Length1 do begin
Temp1 := AArray[Length1 - 1];
System.Move(AArray[Index1], AArray[Index1 + 1], (Length1 - Index1 + 1) * SizeOf(Double));
AArray[Index1] := Temp1;
Index1 := Index1 + 2;
end;
end;
Here is how it (should) work(s) step-by-step
Input AArray: 123456
Index1: 0
Temp1 := 6
System.Move: 112345
AArray: 612345
Index1: 2
Temp1 := 5
System.Move: 612234
AArray: 615234
Index1: 4
Temp1 := 4
System.Move: 615233
AArray: 615243
Output AArray: 615243
For a record structure, such as, TPerson, it would be like this:
procedure SerratedSort(var A: array of TPerson);
var
s: Integer;
i: Integer;
t: TPerson;
begin
s := Length(A);
i := 0;
while i < s do begin
t := A[s - 1];
System.Move(A[i], A[i + 1], (s - i + 1) * SizeOf(TPerson));
A[i] := t;
i := i + 2;
end;
end;
Sort the data in ascending order. Then pick out the values using the following indices: 0, n-1, 1, n-2, ....
In pseudo code the algorithm looks like this:
Sort;
lo := 0;
hi := n-1;
while lo<=hi do
begin
yield lo;
inc(lo);
if lo>hi then break;
yield hi;
dec(hi);
end;
Example program demonstrating the already above given solutions:
program Project1;
{$APPTYPE CONSOLE}
const
Count = 12;
type
TValues = array[0..Count - 1] of Double;
const
Input: TValues = (1,2,4,9,13,14,15,23,60,100,101,102);
var
I: Integer;
Output: TValues;
procedure ShowValues(Caption: String; Values: TValues);
var
I: Integer;
begin
Write(Caption);
for I := 0 to Count - 2 do
Write(Round(Values[I]), ', ');
WriteLn(Round(Values[Count - 1]));
end;
begin
if Odd(Count) then
WriteLn('Cannot compute an odd number of input values')
else
begin
WriteLn('Program assumes sorted input!');
ShowValues('Input: ', Input);
for I := 0 to (Count div 2) - 1 do
begin
Output[2 * I] := Input[I];
Output[2 * I + 1] := Input[Count - 1 - I];
end;
ShowValues('Output: ', Output);
end;
ReadLn;
end.
So this could be hard to explain but i want to do a for ... := 1 to 10 do statement but i want it to be for A to N do. The main purpose of this excersise is to load data into a string grid. So lets have it load the cells 0,1 0,2 0,3 0,4 0,5 0,6 0,7 with the Letter A, B, C, D, E all the way up to 14. If anyone knows how to do this i would be extremely thankful!
Here you got it, but I'm not sure if it's a good way how to learn programming (I mean asking question as requests so that someone else write code for you):
procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
begin
StringGrid1.FixedCols := 1;
StringGrid1.ColCount := 15;
for I := 1 to 14 do
StringGrid1.Cells[I, 1] := Chr(Ord('A') + I - 1);
end;
If you want to fill the StringGrid control one row at a time, you can do
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
StringGrid1.FixedCols := 1;
StringGrid1.FixedRows := 1;
for i := 0 to Min(25, (StringGrid1.ColCount-1) * (StringGrid1.RowCount-1)) do
StringGrid1.Cells[i mod (StringGrid1.ColCount - 1) + 1,
i div (StringGrid1.ColCount - 1) + 1] := Chr(Ord('A') + i);
end;
which works no matter how many rows and cols there are.
Want to fuse TLama's answer with that "want to do a for ... := 1 to 10 do statement but i want it to be for A to N do"
Don't know if it will be pun, or enlightening.
var c: char; i: integer;
s: string;
...
i := 0; s:= EmptyStr;
for c := 'A' to 'N' do begin
s := s + c + ',';
Inc(i);
end;
SetLength(s, Length(s) - 1); // we do not need last comma there
StringGrid1.ColCount := i;
StringGrid1.Rows[0].CommaText := s;
Or the same using TStringBuilder - which would be faster than re-arranging Heap on each new string modification.
uses SysUtils;
...
var c: char; i: integer;
s: string;
...
i := 0;
with TStringBuilder.Create do try
for c := 'A' to 'N' do begin
Append(c + ',');
Inc(i);
end;
s := ToString;
finally
Free;
end;
SetLength(s, Length(s) - 1); // we do not need last comma there
StringGrid1.ColCount := i;
StringGrid1.Rows[0].CommaText := s;