destructor TMedian.Destroy;
var
Group:PGroup;
Number:PNumber;
i:integer;
begin
for i := 0 to self.Groups.Count - 1 do
begin
Group := self.Groups.Items[i];
Dispose(Group);
end;
self.Groups.Free;
for i := 0 to self.Nums.Count - 1 do
begin
Number := self.Nums.Items[i];
Dispose(Number);
end;
self.Nums.Free;
inherited;
end;
//设置组距
procedure TMedian.SetGroupInterval;
var
i,j:Extended;
Number:PNumber;
begin
Number := self.Nums.First;
i := Number^.Num;
Number := self.Nums.Last;
j := Number^.Num;
self.GroupInterval := (j - i)/self.GroupCount;
end;
//设置本组的索引值,组内频数大于N/2,或累计频数大于N/2即为本组
procedure TMedian.SetLocalGroupIndex;
var
Group:PGroup;
i:integer;
HafeN:integer;
begin
HafeN := self.Nums.Count div 2;
for i := 0 to self.GroupCount - 1 do
begin
Group := self.Groups.Items[i];
if Group^.f >= HafeN then
begin
self.LocalGroupIndex := i;
exit;
end;
end;
for i := 0 to self.GroupCount - 1 do
begin
if self.GetTotalFLessThan(i) >= HafeN then
begin
self.LocalGroupIndex := i;
exit;
end;
end;
end;
function TMedian.GetMedian: Extended;
var
HalfN:integer;
X1,X2:PNumber;
Group:PGroup;
begin
//先给输入的数据排序
self.Sort;
//样本数量少时,直接取中位数
if self.Nums.Count <= self.LittleCount then
begin
//样本数量为偶数时的算法
if (self.Nums.Count mod 2) = 0 then
begin
HalfN := (self.Nums.Count div 2) - 1;
X1 := self.Nums.Items[HalfN];
X2 := self.Nums.Items[HalfN + 1];
result := (X1^.Num + X2^.Num)/2;
end
//样本数量为奇数时的算法
else
begin
HalfN := ((self.Nums.Count + 1) div 2) - 1;
X1 := self.Nums.Items[HalfN];
result := X1^.Num;
end;
end
//样本数量多时,另外计算中位数
else
begin
//划分组距
self.SetGroupInterval;
//设置组
self.MakeGroup;
//设置本组索引值
self.SetLocalGroupIndex;
HalfN := self.LocalGroupIndex;
Group := self.Groups.Items[HalfN];
result := Group^.Min + (self.GroupInterval / Group^.f) *
(self.Nums.Count / 2 - self.GetTotalFLessThan(HalfN - 1));
end;
end;
//取某组的累计频数
function TMedian.GetTotalFLessThan(const GroupIndex:integer): integer;
var
Group:PGroup;
i:integer;
begin
result := 0;
for i := 0 to GroupIndex do
begin
Group := self.Groups.Items[i];
result := result + Group^.f;
end;
end;
//划分组
procedure TMedian.MakeGroup;
var
Group:PGroup;
Number:PNumber;
i,j:integer;
Limit:Extended;
begin
//取最小值
Number := self.Nums.First;
Limit := Number^.Num;
//设置每组的上下限
for i := 0 to self.GroupCount - 1 do
begin
new(Group);
Group^.Min := Limit;
Limit := Limit + self.GroupInterval;
Group^.Max := Limit;
Group^.f := 0;
self.Groups.Add(Group);
end;
//设置组频数,i为组的记数,j为数据的记数
i := 0;
j := 0;
while (i < self.GroupCount) and (j < self.Nums.Count) do
begin
Group := self.Groups.Items[i];
Number := self.Nums.Items[j];
//如果数据在当前组内,当前组的频数增一,否则当前组向后移一位
if (Number^.Num >= Group^.Min) and (Number^.Num < Group^.Max) then
begin
Group^.f := Group^.f + 1;
j := j + 1;
end
else
i := i + 1;
end;
end;
//快速排序有问题,所以用了选择排序法
procedure TMedian.Sort;
begin
self.SelectSort;
end;
//快速排序法,不过有问题,排的不对
procedure TMedian.QuickSort(iLo, iHi: integer);
var
Lo, Hi:Integer;
LoNumber,HiNumber,MidNumber:PNumber;
T:Extended;
begin
Lo := iLo;
Hi := iHi;
MidNumber := self.Nums.Items[(Lo + Hi) div 2];
repeat
LoNumber := self.Nums.Items[Lo];
HiNumber := self.Nums.Items[Hi];
while LoNumber^.Num < MidNumber^.Num do
begin
Inc(Lo);
LoNumber := self.Nums.Items[Lo];
end;
while HiNumber^.Num > MidNumber^.Num do
begin
Dec(Hi);
HiNumber := self.Nums.Items[Hi];
end;
if Lo <= Hi then
begin
T := LoNumber^.Num;
LoNumber^.Num := HiNumber^.Num;
HiNumber^.Num := T;
Inc(Lo);
Dec(Hi);
end;
until Lo > Hi;
if Hi > iLo then self.QuickSort(iLo,Hi);
if Lo < iHi then self.QuickSort(Lo,iHi);
end;
//选择法排序
procedure TMedian.SelectSort;
var
INumber,JNumber:PNumber;
T:Extended;
i,j:integer;
begin
for i := 0 to self.Nums.Count - 2 do
for j := self.Nums.Count - 1 downto i + 1 do
begin
INumber := self.Nums.Items[i];
JNumber := self.Nums.Items[j];
if INumber^.Num > JNumber^.Num then
begin
T := INumber^.Num;
INumber^.Num := JNumber^.Num;
JNumber^.Num := T;
end;
end;
end;