请各位帮忙生成这样一颗树.(总共就这些分了,不好意思,下次补上)(60分)

  • 主题发起人 主题发起人 jbas
  • 开始时间 开始时间
J

jbas

Unregistered / Unconfirmed
GUEST, unregistred user!
我想生成这些数
[ x,y ]
/ | | /
[x,y-1] [x,y+1] [x-1,y] [x+1,y]
/ | | / ...........................
[x,y-1-1] [x,y-1+1] [x-1,y-1] [x+1,y-1]
这些[x,y]为屏幕上的某点的坐标.我这里有10个这样的点要扩充.
即屏幕上的某一点向上,下,左,右四个方向扩展,而扩展出的新点又向那四个方向扩展.我想生成这些点的坐标
,不知怎样的算法,用递归,还是什么别的?
小弟不才,搞了很久都不行,总是在这10个点的基础上生成了那40个点,就再也动不了了,请各位
大侠指教了.!
 
不管有多少分支,都是树的概念,如果通过一个树的每个树节点,那就是遍历,
其实大学的数据结构都讲倒过,不过没有什么人会实际结合用.
我们公司的软件招聘题目,我出的,就是树的遍历和逆波兰表达式
 
下面是那个以一个点生成上,下,左,右四个点的函数,返回存储四个点的数组.但怎样继续以生成的点在生成下面的四点呢?
有高手说可以用分形算法,细胞分裂算法.我查了点资料,还是一头雾水.高手们,帮帮忙呀!
type
MyPointArr=array[1..4] of TPoint;
function Tsimulate.MyProc(MyPoint:TPoint):MyPointArr;
var
TempPoint:TPoint;
TempArrStore:MyPointArr;
begin
TempPoint.X:=MyPoint.X;
TempPoint.Y:=MyPoint.Y-1;
TempArrStore[1]:=TempPoint;
TempPoint.X:=MyPoint.X;
TempPoint.Y:=MyPoint.Y+1;
TempArrStore[2]:=TempPoint;
TempPoint.X:=MyPoint.X-1;
TempPoint.Y:=MyPoint.Y;
TempArrStore[3]:=TempPoint;
TempPoint.X:=MyPoint.X+1;
TempPoint.Y:=MyPoint.Y;
TempArrStore[4]:=TempPoint;
result:=TempArrStore;
end;
 
请教各位高手有没有这样的二维数组:
a[i(整数),arr(数组,但可以动态的改变大小)]
例如:
a[1,(a,b)];
a[1,(a,b,c)];
a[2,(a,b,c,d,e)];
如果有,怎样做呀?谢谢!
var
kk:array[1..10,array of integer] of integer;//这样不行呀!
 
依照你的资料,改成用递归调用,如:
function Tsimulate.MyProc(MyPoint:TPoint):MyPointArr;
var
TempPoint:TPoint;
TempArrStore:MyPointArr;
begin
TempPoint.X:=MyPoint.X;
TempPoint.Y:=MyPoint.Y-1;
TempArrStore[1]:=TempPoint;
MyProc(TempPoint);
TempPoint.X:=MyPoint.X;
TempPoint.Y:=MyPoint.Y+1;
TempArrStore[2]:=TempPoint;
MyProc(TempPoint);
TempPoint.X:=MyPoint.X-1;
TempPoint.Y:=MyPoint.Y;
TempArrStore[3]:=TempPoint;
MyProc(TempPoint);
TempPoint.X:=MyPoint.X+1;
TempPoint.Y:=MyPoint.Y;
TempArrStore[4]:=TempPoint;
MyProc(TempPoint);
result:=TempArrStore;
end;

当然,对每一Point的其他处理(如描绘等)也需加在相应TempPoint后。
另: 可以查看《计算机图形学》中关于图形填充算法(如泛滥填充法)的内容。
 
to Yang J.Q.
谢谢关注! 但你那个算法好像还是有问题,因为我不是单纯的一个点来生成这些点,我是好几个点的.
并且这些点的生成要是同步的,虽然不是绝对的同步,但是还是要求第一个点生成4个点后,
第二个接着生成另外的4个点,再第三个......直到第10个点生成4个点后,又要以那
第一个点生成的那四个点中取一个来生成另外的4个点.再在第一个点生成的那四个点中取另外一个点来生成另外
的4个点....直到第一个点生成的那四个点全部生成完,在以那个原先第一轮生成的第二个点重复下去...
所以你那样的在每一个点生成后就MyProc(TempPoint);就会导致以这个点为根节点,连续生成点下去,
而不是先遍历那10个点,那10*4个点,那10*4*4个点......在以那些点来生成别的点了.
我好象只能先把那些点先生成存储在一个数组中,然后在从那个数组中去出这些点来操作,
而不能直接对生成的点来操作?
继续征求大侠们的意见....
 
请教各位高手有没有这样的二维数组:
a[i(整数),arr(数组,但可以动态的改变大小)]
例如:
a[1,(a,b)];
a[1,(a,b,c)];
a[2,(a,b,c,d,e)];
如果有,怎样做呀?谢谢!
var
kk:array[1..10,array of integer] of integer;//这样不行呀!
 
版主creation-zy,帮帮忙了!
 
我觉得算法的关键是数据存取的问题,所以每一个结点都必须包括六部分内容,x坐标,y坐标
及指向下四个结点的指针。关于具体的算法,你想想吧
不知对你有没有帮助!
 
我已经写了一个大概这样东西,还在改进中!
http://www26.brinkster.com/jbaswjy
 
老大,你的网页我看不到。
可以用链表,很方便的。
Working...
另:终止条件是什么?这样下去除了控制深度,似乎没有什么可以让它停下来,是不是
已经取过的点就不能再取了?
 
版主大哥:
 我这个现在已经完成的查不多了,已经能产生效果了.下一步要改的也就是让它按什么形状生长了,如果可能还
想改一下那个算法.
我在那里控制停止是控制它分裂的次数,这样我觉的可以,因为如果安某种规定,很可能死机的.运算次数非常多.
>>是不是已经取过的点就不能再取了?
我的第一个算法中,没有排除相同的点,按4^n产生点,速度挺慢,而且最多分裂9次.(duron 700,128M,win2000)
我的第二个算法中,排除了相同的点.按4*n产生点.速度成比例的快起来了,分裂30次还没有死机.
源代码:
http://jbas.delphibbs.com或http://www26.brinkster.com/jbaswjy/source2.rar
如果看不到,我帖上来了.
 
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls,globunit,Math;
type
Tsimulate = class(TForm)
Panel1: TPanel;
Button1: TButton;
pntbx: TPaintBox;
sjzd: TButton;
Label1: TLabel;
Button3: TButton;
initial: TButton;
procedure FormCreate(Sender: TObject);
procedure initialClick(Sender: TObject);
procedure sjzdClick(Sender: TObject);
private
procedure MyProc(MyPoint:TPoint;MyColor:Tcolor);
{ Private declarations }
public
{ Public declarations }
end;

var
simulate: Tsimulate;
implementation
{$R *.dfm}
function PointBorn(ThePoint:TPoint):TArrPoint;
var
TempPoint:TPoint;
TempArrPoint:TArrPoint;
begin
TempPoint.X:=ThePoint.X-1;
TempPoint.Y:=ThePoint.Y;
TempArrPoint[0]:=TempPoint;
TempPoint.X:=ThePoint.X;
TempPoint.Y:=ThePoint.Y-1;
TempArrPoint[1]:=TempPoint;
TempPoint.X:=ThePoint.X+1;
TempPoint.Y:=ThePoint.Y;
TempArrPoint[2]:=TempPoint;
TempPoint.X:=ThePoint.X;
TempPoint.Y:=ThePoint.Y+1;
TempArrPoint[3]:=TempPoint;
Result:=TempArrPoint;
end;

Procedure Tsimulate.MyProc(MyPoint:TPoint;MyColor:Tcolor);
begin
if simulate.pntbx.Canvas.Pixels[MyPoint.X,MyPoint.Y]=MyclColor then
simulate.pntbx.Canvas.Pixels[MyPoint.X,MyPoint.Y]:=MyColor;
end;

procedure Tsimulate.FormCreate(Sender: TObject);
begin
end;

{初始化ArrStorePoint,填入开始的坐标.[I,1],[I,2]}
procedure Tsimulate.initialClick(Sender: TObject);
var
X,Y,I,J,K,T,Q,E,F,PCount,PBle1,PBle2,PBle3:integer;
ArrPoint:TArrPoint;
TempPointStore:array of TPoint;
OutFlag:boolean;
begin
{填充色彩.}
for I:=0 to simulate.pntbx.Widthdo
begin
for J:=0 to simulate.pntbx.Heightdo
simulate.pntbx.Canvas.Pixels[I,J]:=MyclColor;
end;
setlength(ArrStorPoint,StartCore,5);
randomize;
for I:=0 to StartCore-1do
begin
X:=Random(simulate.pntbx.Width);
Y:=Random(simulate.pntbx.Height);
ArrStorPoint[I,0]:=point(X,Y);
simulate.pntbx.Canvas.Pixels[X,Y]:=ArrColorType;
ArrPoint:=PointBorn(ArrStorPoint[I,0]);
//第一次分裂.
for J:=1 to 4do
ArrStorPoint[I,J]:=ArrPoint[J-1];
end;
{初始化ArrStorePoint,把全部的点的坐标存储起来.}
for T:=1 to SpltCountdo
//第二次分裂开始.
begin
PCount:=4*T;
//需要分裂点的个数.
PBle1:=2*T*(T-1)+1;
//这次分裂开始点.
PBle2:=2*T*(T+1)+1;
//下一层的最左边的点.
PBle3:=2*(T+2)*(T+3)+1;
//需要存储的总共的点数.
setlength(ArrStorPoint,StartCore,PBle3);
for I:=0 to StartCore-1do
begin
Q:=0;
//表示为一层分裂后的总点数.8,12,16...
for J:=0 to PCount-1do
begin
application.ProcessMessages;
ArrPoint:=PointBorn(ArrStorPoint[I,PBle1+J]);
for K:=0 to 3do
begin
//过滤个别点.
OutFlag:=False;
//检查是否与上一层有相同的点.
for F:=0 to (PBle2-1)do
begin
if (ArrPoint[K].X=ArrStorPoint[I,F].X) and (ArrPoint[K].Y=ArrStorPoint[I,F].Y) then
OutFlag:=True;
end;
//检查是否与这一层的上一个点的扩展点有相同的点.
for F:=0 to Q-1do
begin
if (ArrPoint[K].X=TempPointStore[F].X) and (ArrPoint[K].Y=TempPointStore[F].Y) then
OutFlag:=True;
end;
//检查是否与这一层的这个点的其它点有相同的点.
for F:=0 to K-1do
begin
if (ArrPoint[K].X=ArrPoint[F].X) and (ArrPoint[K].Y=ArrPoint[F].Y) then
OutFlag:=True;
end;
if OutFlag=False then
begin
Q:=Q+1;
setlength(TempPointStore,Q);
TempPointStore[Q-1]:=ArrPoint[K];
end;
end;
end;
for E:=0 to Q-1do
ArrStorPoint[I,(PBle2+E)]:=TempPointStore[E];
end;
end;
application.MessageBox('完成初始化任务!','提醒窗口',0);
end;

procedure Tsimulate.sjzdClick(Sender: TObject);
var
I,J,K,M,PBle:integer;
begin
for I:=1 to SpltCountdo
begin
PBle:=2*I*(I-1)+1;
//最左边的点.
M:=4*I;
for K:=0 to StartCore-1do
begin
for J:=0 to M-1do
begin
application.ProcessMessages;
simulate.MyProc(ArrStorPoint[K,PBle+J],ArrColorType[K]);
end;
end;
end;
application.MessageBox('初始化完成!','提醒窗口',0);
end;

end.
 
unit globunit;
interface
uses Graphics,Types;
type
TArrPoint=array[0..3] of TPoint;
const
StartCore=10;
// 初始晶核数.
SpltCount=50;
//分裂次数.
MyclColor=clwhite;
var
ArrColorType:array[0..9] of Tcolor=(clblack,clgreen,clnavy,clred,clyellow
,clblue,clskyblue,clinfobk,clMoneyGreen,clcream);//用来存储晶核的颜色.
ArrStorPoint:array of array of TPoint;
implementation

end.
 
和数有关的,一般递归简单
 
谢谢版主老大的鼎立相助!
小弟试了你的程序,运行良好.我想说说我的对比:
1:你在程序中,自己定义了一个类,完全实现了存点,取点,扩展点的功能,而我一点都没有oop的思想
,要什么就都写在了form中,程序不清晰.而当时自己也完全没有自己要设计一个类的想法,
不知什么时候会有这种思想,嗨.....
2:老大这个结构什么意思呀?
PXYLink=^XYLink;
XYLink=record
X,Y,Tag:Integer;
Next:PXYLink;//跟上面的PXYLink有关系吗?
end;
3:你是通过什么把点存进FMemImg的. procedure SetPoint(X,Y:Integer;Value:Integer=0);
没有用到呀?通过传地址????
4:你是通过扫描全部的点,然后判断是否与FMemImg中存的东西有相同的,再进行操作,而我
的是通过设定的分裂次数,起始点的多少,这次分裂的点数来进行操作的.是麻烦了点,而且还
要通过计算(基本的等差数列),但效率好象不低,而且只要初始化完成(这个得等一会,根据
那个初始条件来确定),那个生长过程非常的快,比你的那个快多了,增加点以后,只是
变了初始化的速度,那个生长的速度没有多大的改变,这个比较符合生长规律.
5:老大你那个增加点太麻烦了,增加一个点还要写一个语句,而我的只要改一下数,就可以
这样可偷懒呢!:)
6:老大你把image控件改为paintbox控件吧,这样就没有闪烁了.
............
我还在研究您的代码,希望多吸取点东西,老大:我有说错的地方请指教呀!
BTW:
有一点我觉的太亏了,我花了3天的功夫,写这个破东西,而老大只用了1个小时还不到就写
完了,心理不平衡.[:(!]
 
1.不要着急,编程思想这种东西是要慢慢培养的。向前看,坚定的走下去!
2.这是在Pascal中定义链表的标准代码。
PXYLink=^XYLink;
//定义一个结构体指针类型
XYLink=record
X,Y,Tag:Integer;
Next:PXYLink;//表明Next是一个指针,指向的对象类型就是XYLink。
//由于此处XYLink的定义还没有完成,因此不能直接使用 Next:^XYLink;
//只能通过上面的PXYLink中转
end;

3.哈哈,在这里呀:
for i:=0 to FWidth-1do
begin
SetLength(FMemImg,FHeight);
FillChar(FMemImg[0],FHeight*SizeOf(Integer),0);
//将二维数组初始化为全0
end;
初始化之后,数组中的元素就全都是clBlack。
4.>>生长过程非常的快,比你的那个快多了
我并不这么认为喲~。我上面的例子之所以感觉不快,并不是因为PointList.ExpandPointList;
过程太慢,而是在每次扩展之后进行绘图的过程太慢了。不信的话你可以在for x:=0 to 199do
一句之前加上“if i=100 then
”——我这里大约0.2秒就搞定了。如果完全将绘图过程删除,
整个过程在毫秒级的时间内就完成了——还不够快吗?
我没有仔细的研究你的程序,但是你的算法中采用了4重循环,而我的只有2重循环(每次扩展
只要一重循环),效率熟高熟低就不用实验了吧。(把你的思路大致说明一下吧,“初始化”
过程有什么作用?)
5.??我已经进行了很完整的封装,如果你要的是随机的效果,完全可以像你一样将
AddSeekPoint过程放在循环里随机取点,我看不出有什么麻烦的地方。
6.我这里没有任何闪烁。
BTW.——冰冻三尺,非一日之寒。世界上有几个真正的天才?大家都是“冻”出来的!
 
{
名称:TXYLink
功能:实现多个种子点在二维平面上的扩展效果,每个种子点可以有不同的颜色
作者:creation_zy
}
type
PXYLink=^XYLink;
XYLink=record
X,Y,Tag:Integer;
Next:PXYLink;
end;
TXYLink=class
private
FPXYLink:PXYLink;
FMemImg:array of array of Integer;
FWidth,FHeight:Integer;
FDefaultTag:Integer;
procedure FreeList(var PList:PXYLink);
procedure AddPointToList(X,Y,Tag:Integer;var PList:PXYLink);
public
procedure AddSeekPoint(X,Y,Tag:Integer);
procedure SetPoint(X,Y:Integer;Value:Integer=0);
function GetPoint(X,Y:Integer):Integer;
procedure ExpandPointList;
constructor Create(Width,Height,DefaultTag:Integer);
destructor Destroy;
override;
end;

{ TXYLink }
procedure TXYLink.AddPointToList(X, Y, Tag: Integer;
var PList: PXYLink);
var
m:PXYLink;
begin
New(m);
m.X:=X;
m.Y:=Y;
m.Tag:=Tag;
m.Next:=PList;
PList:=m;
end;

procedure TXYLink.AddSeekPoint(X, Y, Tag: Integer);
begin
AddPointToList(X,Y,Tag,FPXYLink);
end;

constructor TXYLink.Create(Width, Height, DefaultTag: Integer);
var
i:Integer;
begin
FPXYLink:=nil;
FWidth:=Width;
FHeight:=Height;
FDefaultTag:=DefaultTag;
SetLength(FMemImg,FWidth);
for i:=0 to FWidth-1do
begin
SetLength(FMemImg,FHeight);
FillChar(FMemImg[0],FHeight*SizeOf(Integer),0);
end;
end;

destructor TXYLink.Destroy;
var
i:Integer;
begin
FreeList(FPXYLink);
for i:=0 to FWidth-1do
SetLength(FMemImg,0);
SetLength(FMemImg,0);
inherited;
end;

procedure TXYLink.ExpandPointList;
var
Head,pm:PXYLink;
procedure TestAndAdd(x0,y0,tag:Integer);
begin
if (x0>=0) and (x0<FWidth) and (y0>=0) and (y0<FHeight) then
if FMemImg[x0][y0]=FDefaultTag then
//如果不等于默认值,则执行扩散
begin
AddPointToList(x0,y0,tag,Head);
FMemImg[x0][y0]:=tag;
end;
end;
begin
Head:=nil;
pm:=FPXYLink;
while pm<>nildo
begin
with pm^do
begin
TestAndAdd(X-1,Y,Tag);
TestAndAdd(X+1,Y,Tag);
TestAndAdd(X,Y-1,Tag);
TestAndAdd(X,Y+1,Tag);
end;
pm:=pm.Next;
end;
FreeList(FPXYLink);
FPXYLink:=Head;
end;

procedure TXYLink.FreeList(var PList: PXYLink);
var
m:PXYLink;
begin
m:=PList;
while m<>nildo
begin
m:=PList.Next;
Dispose(PList);
PList:=m;
end;
PList:=nil;
end;

function TXYLink.GetPoint(X, Y: Integer): Integer;
begin
Result:=FMemImg[X][Y];
end;

procedure TXYLink.SetPoint(X, Y: Integer;
Value: Integer);
begin
FMemImg[X][Y]:=Value;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
PointList:TXYLink;
i,x,y:Integer;
begin
PointList:=TXYLink.Create(200,200,Integer(clBlack));
//Integer(clBlack))=0
PointList.AddSeekPoint(20,60,Integer(clWhite));
PointList.AddSeekPoint(150,100,Integer(clRed));
PointList.AddSeekPoint(80,130,Integer(clBlue));
PointList.AddSeekPoint(99,133,Integer(clGreen));
PointList.AddSeekPoint(166,39,Integer(rgb(50,150,255)));
PointList.AddSeekPoint(77,150,Integer(rgb(100,230,200)));
with Image1.Canvasdo
for i:=1 to 100do
//扩展100次
begin
PointList.ExpandPointList;
for x:=0 to 199do
for y:=0 to 199do
Pixels[x,y]:=TColor(PointList.GetPoint(x,y));
Application.ProcessMessages;
end;
PointList.Free;
end;

满意否? :)
 
老大教训的是,小弟努力之.
那个初始的过程主要是用来将那些生成的点都存到ArrStorPoint这个数组中!
例如:
a[0,0]= [x,y]
|
--------------------------------------------------------------------
| | | |
a[0,1]=[x-1,y-1] a[0,2]=[x,y-1] a[0,3]=[x+1,y] a=[0,4]=[x,y+1]
| |
--------------   ----------------
| | | |   | | | |
a[0,5]=[x-2,y]4个点.[x-1,y-1](有了,就过滤掉)..............
上面的a[0,1],a[0,5],a[0,13]....中的1,5,13...通过计算可以出来.
a[0,1],a[0,5]......这层上的点的总数可以通过等差数列计算出来.通过初始化,把那些生长的
并且过滤过的点存到 ArrStorPoint这个数组中.
在onclick事件中,就是遍历那个ArrStorPoint数组,取出其中的点来处理.
这个程序还只是个开始,那些点还有用,用来处理别的过程.
谢谢版主的支持!
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
后退
顶部