新普金娱乐Pascal数据结构与算法。

率先段 数据结构与算法的引入

算法大全(C,C++)
一如既往、 数论算法
 
1.求星星频的最大公约数
function gcd(a,b:integer):integer;
begin
if b=0 then gcd:=a
else gcd:=gcd (b,a mod b);
end ;

1.1 数据结构的基本概念

2.求简单勤的最小公倍数
function lcm(a,b:integer):integer;
begin
if a<b then swap(a,b);
lcm:=a;
while lcm mod b>0 do inc(lcm,a);
end;

相同、 学习数据结构的含义

3.素数之求法
A.小范围外判断一个屡次是否也质数:
function prime (n: integer): Boolean;
var I: integer;
begin
for I:=2 to trunc(sqrt(n)) do
if n mod I=0 then begin
prime:=false; exit;
end;
prime:=true;
end;

    程序设计 = 数据结构 + 算法

B.判断longint范围外的一再是否为素数(包含呼吁50000坐内之素数表):
procedure getprime;
var
i,j:longint;
p:array[1..50000] of boolean;
begin
fillchar(p,sizeof(p),true);
p[1]:=false;
i:=2;
while i<50000 do begin
if p[i] then begin
j:=i*2;
while j<50000 do begin
p[j]:=false;
inc(j,i);
end;
end;
inc(i);
end;
l:=0;
for i:=1 to 50000 do
if p[i] then begin
inc(l);pr[l]:=i;
end;
end;{getprime}

当下,80%底得处理的数有所“算法简单”(四虽然运算、检索、排序等),“对象复杂”(数据类型不同、数据量大、需要保留)等特性,故合理组织数据、选择比较好的数据结构可为高效算法(时间掉、占用空间小)提供不错的对象。

function prime(x:longint):integer;
var i:integer;
begin
prime:=false;
for i:=1 to l do
if pr[i]>=x then break
else if x mod pr[i]=0 then exit;
prime:=true;
end;{prime}

 

第二、图论算法

次、基本术语

1.极度小生成树

1.数据(data):

A.Prim算法:

 
是针对性客观事物的符的表示,是兼具能够输入到计算机被连给电脑程序处理的号的总称。(P1表1-1受,学号、姓名、性别、民族等列为字符型数据,语文、数学等列为数值型数据)

procedure prim(v0:integer);
var
lowcost,closest:array[1..maxn] of integer;
i,j,k,min:integer;
begin
for i:=1 to n do begin
lowcost[i]:=cost[v0,i];
closest[i]:=v0;
end;
for i:=1 to n-1 do begin
{寻找离生成树最近底免入顶点k}
min:=maxlongint;
for j:=1 to n do
if (lowcost[j]<min) and (lowcost[j]<>0) then begin
min:=lowcost[j];
k:=j;
end;
lowcost[k]:=0; {将顶点k加入生成树}
{生成树中长一长条新的边k到closest[k]}
{修正各点的lowcost和closest值}
for j:=1 to n do
if cost[k,j]<lwocost[j] then begin
lowcost[j]:=cost[k,j];
closest[j]:=k;
end;
end;
end;{prim}

表明1-1  学生档案

B.Kruskal算法:(贪心)

学号

姓名

性别

民族

语文

数学

英语

总成绩

101

张华

汉族

104.5

124

115

 

102

郝博

汉族

113

125

94.5

 

 

303

白晓燕

朝鲜族

96

105

135

 

比如权值递增顺序删去图中的度,若无形成回路则将此边加入最小生成树。
function find(v:integer):integer; {返回顶点v所在的聚合}
var i:integer;
begin
i:=1;
while (i<=n) and (not v in vset[i]) do inc(i);
if i<=n then find:=i else find:=0;
end;

 

procedure kruskal;
var
tot,i,j:integer;
begin
for i:=1 to n do
vset[i]:=[i];{初始化定义n个集合,第I个聚众包含一个元素I}
p:=n-1; q:=1; tot:=0; {p为尚需要在的边数,q为边集指针}
sort;
{对富有边按权值递增排序,存于e[I]中,e[I].v1与e[I].v2也边I所连接的蝇头独顶峰的序号,e[I].len也第I条边的长短}
while p>0 do begin
i:=find(e[q].v1);j:=find(e[q].v2);
if i<>j then begin
inc(tot,e[q].len);
vset[i]:=vset[i]+vset[j];vset[j]:=[];
dec(p);
end;
inc(q);
end;
writeln(tot);
end;

  1. 数据项(data item)

2.极度缺乏路径

数量项是多少不可分割的极小单位。(P1表1-1着之一个字段就是一个数码项)

A.标号法求解单源点最短缺路径:
var
a:array[1..maxn,1..maxn] of integer;
b:array[1..maxn] of integer; {b[i]指顶点i到源点的极其缺路径}
mark:array[1..maxn] of boolean;

3.数据元素(data element):
 是数据的中心单位,在处理器程序中便作为一个总体来拍卖。一个数额元素由多只数据项构成,(P1表1-1受到的一致履行就是是一个数量元素)

procedure bhf;
var
best,best_j:integer;
begin
fillchar(mark,sizeof(mark),false);
mark[1]:=true; b[1]:=0;{1为源点}
repeat
best:=0;
for i:=1 to n do
If mark[i] then {对各级一个都算起极短缺路径的触及}
for j:=1 to n do
if (not mark[j]) and (a[i,j]>0) then
if (best=0) or (b[i]+a[i,j]<best) then begin
best:=b[i]+a[i,j]; best_j:=j;
end;
if best>0 then begin
b[best_j]:=best;mark[best_j]:=true;
end;
until best=0;
end;{bhf}

4.数据结构(data structure):

B.Floyed算法求解所有终端对中间的绝短路径:
procedure floyed;
begin
for I:=1 to n do
for j:=1 to n do
if a[I,j]>0 then p[I,j]:=I else p[I,j]:=0;
{p[I,j]意味着I到j的极其缺少路径上j的前人结点}
for k:=1 to n do {枚举中间结点}
for i:=1 to n do
for j:=1 to n do
if a[i,k]+a[j,k]<a[i,j] then begin
a[i,j]:=a[i,k]+a[k,j];
p[I,j]:=p[k,j];
end;
end;

大凡彼此有同样种或又一定关系之数码元素的集纳。数据结构是一个二元组,记否:
B=(D,S).其中D为数据元素的会师,S是D上干的会师。

C. Dijkstra 算法:

数量元素相互之间的干称为组织(structure)。根据数据元素中涉及的差特点,通常由下列四类基本构造:

var
a:array[1..maxn,1..maxn] of integer;
b,pre:array[1..maxn] of integer; {pre[i]仰太缺乏路径上I的前人结点}
mark:array[1..maxn] of boolean;
procedure dijkstra(v0:integer);
begin
fillchar(mark,sizeof(mark),false);
for i:=1 to n do begin
d[i]:=a[v0,i];
if d[i]<>0 then pre[i]:=v0 else pre[i]:=0;
end;
mark[v0]:=true;
repeat {每循环一赖加入一个离1集合最近底结点并调整其他结点的参数}
min:=maxint; u:=0; {u记录离1集合最近底结点}
for i:=1 to n do
if (not mark[i]) and (d[i]<min) then begin
u:=i; min:=d[i];
end;
if u<>0 then begin
mark[u]:=true;
for i:=1 to n do
if (not mark[i]) and (a[u,i]+d[u]<d[i]) then begin
d[i]:=a[u,i]+d[u];
pre[i]:=u;
end;
end;
until u=0;
end;

(1)集合:数据元素中的干是同属一个聚。(图1)

3.计算图的传递闭包

(2)线性结构:数据元素中在一定底关系。(图2)

Procedure Longlink;
Var
T:array[1..maxn,1..maxn] of boolean;
Begin
Fillchar(t,sizeof(t),false);
For k:=1 to n do
For I:=1 to n do
For j:=1 to n do T[I,j]:=t[I,j] or (t[I,k] and t[k,j]);
End;

(3)树形结构:结构中的元素中的涉嫌是同针对性几近之涉及。(图3)

4.无向图的接分量

(4)图(网)状组织:结构被之素中的干是差不多针对多之涉嫌。(图4)

A.深度优先
procedure dfs ( now,color: integer);
begin
for i:=1 to n do
if a[now,i] and c[i]=0 then begin {对结点I染色}
c[i]:=color;
dfs(I,color);
end;
end;

 

B 宽度优先(种子染色法)

    图1           图2            图3                 图4 

5.生死攸关路径

                                                      

几单概念: 顶点1乎源点,n为汇点。
a. 顶点事件极早产生时间Ve[j], Ve [j] = max{ Ve [j] + w[I,j]
},其中Ve (1) = 0;
b. 顶点事件极晚发出时间 Vl[j], Vl [j] = min{ Vl[j] – w[I,j]
},其中 Vl(n) = Ve(n);
c. 边走极早开始日 Ee[I], 若边I由<j,k>表示,则Ee[I] =
Ve[j];
d. 边走最好晚开始时 El[I], 若边I由<j,k>表示,则El[I] =
Vl[k] – w[j,k];
若 Ee[j] = El[j]
,则运动j为机要活动,由重点活动做的门道也重大路径。
求解方法:
a. 从源点起topsort,判断是否来回路并盘算Ve;
b. 从汇点起topsort,求Vl;
c. 算Ee 和 El;

  1. 多少的逻辑结构和情理结构

6.拓扑排序

逻辑结构:数据元素中存在 的关系(逻辑关系)叫数据的逻辑结构。

探寻入度为0的接触,删去与该相连的具有边,不断重复这同样历程。
例 寻找相同屡次排列,其中任意连续p项之同为正,任意q
项之与也倚,若不在则输出NO.

大体构造:数据结构在微机被的象征(映象)叫数据的情理构造。

7.回路题材

相同栽逻辑结构可映象成不同的存储结构:顺序存储结构以及非顺序存储结构(链式存储结构)。

Euler回路(DFS)
概念:经过图的每条边仅一不良的回路。(充要条件:图连同且无奇点)

⑴. 顺序存储结构:
是指用一片连续的存储单元依次存储线性表的每要素,通常由数组实现。它是随首址加位移来访问每个元素。

Hamilton回路
概念:经过图的每个终端仅一坏的回路。

假若有线性表的每要素存入一维数组中,且每个元素a[i]占用l个单元

一笔画
充要条件:图并通且奇点个数为0个或2单。

    a[c],  a[c+1], … , a[i],  …   a[n]

9.判断图中是否生负权回路 Bellman-ford 算法

b     b+ l     b+(i-1) l   ,b+(n-1) l

x[I],y[I],t[I]各自表示第I条边的起点,终点与权。共n个结点和m条边。
procedure bellman-ford
begin
for I:=0 to n-1 do d[I]:=+infinitive;
d[0]:=0;
for I:=1 to n-1 do
for j:=1 to m do {枚举每一样长边}
if d[x[j]]+t[j]<d[y[j]] then
d[y[j]]:=d[x[j]]+t[j];
for I:=1 to m do
if d[x[j]]+t[j]<d[y[j]] then return false else return
true;
end;

 

10.第n极其短缺路径问题

则a[i] 的地址 LOC(a[i]) =
LOC(a[c]) + (i-c)*l = b+(i-c) l

*亚无比短路径:每举最短路径上之各级条边,每次去一长达,然后要新图的最好短缺路径,取这些途径中最好缺乏的等同长就算为次最短路径。
*同理,第n最缺少路径而当求解第n-1绝短缺路径的底子及求解。

                        首地址     位移 

老三、背包问题

 

*一部分背包问题可出贪心法求解:计算Pi/Wi
数据结构:
w[i]:第i个背包的份量;
p[i]:第i单背包的价;

例如:var

1.0-1背着包: 每个背包只能动用相同糟糕或有限次(可转化为同样涂鸦):

       a :array[4..100] of integer;

A.求最多但是放入的重量。
NOIP2001 装箱问题
产生一个箱容量为v(正整数,o≤v≤20000),同时出n个物品(o≤n≤30),每个物品有一个体积
(正整数)。要求自 n
个物品中,任取若千独装箱内,使箱子的多余空间吗最小。
l 搜索方法
procedure search(k,v:integer); {搜索第k独物品,剩余空间为v}
var i,j:integer;
begin
if v<best then best:=v;
if v-(s[n]-s[k-1])>=best then exit; {s[n]也前n个物品的重和}
if k<=n then begin
if v>w[k] then search(k+1,v-w[k]);
search(k+1,v);
end;
end;

       已知:a[4]的地点也x,

l DP
F[I,j]否眼前i个物品中摘多单放入使其体积正好呢j的表明,为布尔型。
实现:将无限优化问题转化为判定性问题
f [I, j] = f [ i-1, j-w[i] ] (w[I]<=j<=v)
边界:f[0,0]:=true.
For I:=1 to n do
For j:=w[I] to v do F[I,j]:=f[I-1,j-w[I]];
优化:当前状态才跟前面一模一样级状态有关,可退到同维。
F[0]:=true;
For I:=1 to n do begin
F1:=f;
For j:=w[I] to v do
If f[j-w[I]] then f1[j]:=true;
F:=f1;
End;

      则 LOC(a[15]) = LOC(a[4]) +(15- 4)*2 = x+22

B.求可以放入的极端深价值。
F[I,j] 为容量也I时取前j个背包所能够取的不过要命价值。
F [i,j] = max { f [ i – w [ j ], j-1] + p [ j ], f[ i,j-1] }

        

C.求恰好装满的场面屡屡。
DP:
Procedure update;
var j,k:integer;
begin
c:=a;
for j:=0 to n do
if a[j]>0 then
if j+now<=n then inc(c[j+now],a[j]);
a:=c;
end;

条例一:删除一个数组中保有的X

2.可另行背包

Program delx;

A求最好多而是放入的份量。
F[I,j]啊眼前i个物品被精选多单放入使其体积正好呢j的表明,为布尔型。
状态转移方程为
f[I,j] = f [ I-1, j – w[I]*k ] (k=1.. j p w[I])

var

B.求可以放入的极端特别价值。
USACO 1.2 Score Inflation
进行相同破交锋,总时间T固定,有多栽而选的问题,每种题目可选入的多寡不限,每种题目来一个ti(解答之开所欲的光阴)和一个si(解答这个开所得之分数),现要选多问题,使解这些书的总时间在T以内的前提下,所得的总分最充分,求最好要命之得分。
*易想到:
f[i,j] = max { f [i- k*w[j], j-1] + k*p[j] } (0<=k<= i p
w[j])
其中f[i,j]代表容量也i时取前j种背包所能够落得的不过深价值。
*实现:
Begin
FillChar(f,SizeOf(f),0);
For i:=1 To M Do
For j:=1 To N Do
If i-problem[j].time>=0 Then
Begin
t:=problem[j].point+f[i-problem[j].time];
If t>f[i] Then f[i]:=t;
End;
Writeln(f[M]);
End.

s:array[1..100]of integer;

C.求恰好装满的状态屡屡。
Ahoi2001 Problem2
伸手自然数n本质不同之质数和之表达式的多寡。
思路一致,生成每个质数的系数的排,在各个测试,这是通法。
procedure try(dep:integer);
var i,j:integer;
begin
cal; {此过程计算时系数的乘除结果,now也结果}
if now>n then exit; {剪枝}
if dep=l+1 then begin {生成有系数}
cal;
if now=n then inc(tot);
exit;
end;
for i:=0 to n p pr[dep] do begin
xs[dep]:=i;
try(dep+1);
xs[dep]:=0;
end;
end;

i,j,n,x:integer;

思路二,递归搜索频率比高
procedure try(dep,rest:integer);
var i,j,x:integer;
begin
if (rest<=0) or (dep=l+1) then begin
if rest=0 then inc(tot);
exit;
end;
for i:=0 to rest p pr[dep] do
try(dep+1,rest-pr[dep]*i);
end;
{main: try(1,n); }

begin

思路三:可应用动态规划求解
USACO1.2 money system
V个物品,背包容量为n,求放法总数。
换方程:

readln(n);

Procedure update;
var j,k:integer;
begin
c:=a;
for j:=0 to n do
if a[j]>0 then
for k:=1 to n p now do
if j+now*k<=n then inc(c[j+now*k],a[j]);
a:=c;
end;
{main}
begin
read(now); {读入第一个物品的份额}
i:=0; {a[i]否背包容量也i时底放法总数}
while i<=n do begin
a[i]:=1; inc(i,now); end;
{定义第一单物品又的整数倍之轻重a值吗1,作为初值}
for i:=2 to v do
begin
read(now);
update; {动态更新}
end;
writeln(a[n]);

for i:=1 to n do begin read(s[i]);write(s[i]:5) end;

季、排序算法

readln(x);

A.快速排序:

i:=1;

procedure qsort(l,r:integer);
var i,j,mid:integer;
begin
i:=l;j:=r; mid:=a[(l+r) p 2]; {将眼前排在中游位置的数定义为中等数}
repeat
while a[i]<mid do inc(i); {在多数局部搜索比中数非常之频繁}
while a[j]>mid do dec(j);{在右侧半组成部分寻找比中数略的数}
if i<=j then begin {若找到同样组及排序目标不一致的高频针对性则交换其}
swap(a[i],a[j]);
inc(i);dec(j); {继续找}
end;
until i>j;
if l<j then qsort(l,j); {若未及一定量个数之鄂,则递归搜索左右距离}
if i<r then qsort(i,r);
end;{sort}

while i<=n do  if s[i]<>x then i:=i+1

B.插入排序:

else begin

思路:当前a[1]..a[i-1]已破好程序了,现要插入a[i]使a[1]..a[i]有序。
procedure insert_sort;
var i,j:integer;
begin
for i:=2 to n do begin
a[0]:=a[i];
j:=i-1;
while a[0]<a[j] do begin
a[j+1]:=a[j];
j:=j-1;
end;
a[j+1]:=a[0];
end;
end;{inset_sort}

for j:=i to n-1 do s[j]:=s[j+1];

C.选择排序:
procedure sort;
var i,j,k:integer;
begin
for i:=1 to n-1 do
for j:=i+1 to n do
if a[i]>a[j] then swap(a[i],a[j]);
end;

n:=n-1;

D. 冒泡排序
procedure bubble_sort;
var i,j,k:integer;
begin
for i:=1 to n-1 do
for j:=n downto i+1 do
if a[j]<a[j-1] then swap( a[j],a[j-1]);
{每次比相邻元素的关系}
end;

end;

E.堆排序:
procedure sift(i,m:integer);{调整为i为根之子树成为堆,m为结点总数}
var k:integer;
begin
a[0]:=a[i];
k:=2*i;{在一点一滴二叉树被结点i的左孩子为2*i,右孩子吧2*i+1}
while k<=m do begin
if (k<m) and (a[k]<a[k+1]) then
inc(k);{找出a[k]与a[k+1]吃于生价值}
if a[0]<a[k] then begin a[i]:=a[k];i:=k;k:=2*i; end
else k:=m+1;
end;
a[i]:=a[0]; {将彻底在合适的职务}
end;

for i:=1 to n do write(s[i],’  ‘);

procedure heapsort;
var
j:integer;
begin
for j:=n p 2 downto 1 do sift(j,n);
for j:=n downto 2 do begin
swap(a[1],a[j]);
sift(1,j-1);
end;
end;

writeln;writeln(‘n=’,n)

F. 归并排序
{a为序列表,tmp为扶助数组}
procedure merge(var a:listtype; p,q,r:integer);
{将早已排序好的子序列a[p..q]与a[q+1..r]联合为平稳的tmp[p..r]}
var I,j,t:integer;
tmp:listtype;
begin
t:=p;i:=p;j:=q+1;{t为tmp指针,I,j分别吗左右子序列的指针}
while (t<=r) do begin
if (i<=q){左序列有结余} and ((j>r) or (a[i]<=a[j]))
{满足获左边序列当前元素的要求}
then begin
tmp[t]:=a[i]; inc(i);
end
else begin
tmp[t]:=a[j];inc(j);
end;
inc(t);
end;
for i:=p to r do a[i]:=tmp[i];
end;{merge}

end.

procedure merge_sort(var a:listtype; p,r: integer);
{合并排序a[p..r]}
var q:integer;
begin
if p<>r then begin
q:=(p+r-1) p 2;
merge_sort (a,p,q);
merge_sort (a,q+1,r);
merge (a,p,q,r);
end;
end;
{main}
begin
merge_sort(a,1,n);
end.

 

G.基数排序
想想:对每个元素以自没有到高位对每一样各类进行相同次排序

⑵.链式存储结构:
当线性表的结点很多还经常要开展扦插、删除操作时用数组表示线性表运算颇为费时,此时可用链式存储结构存储线性表,一般用动态指针实现。

五、高精度计算

     

愈精度往往之概念:
type
hp=array[1..maxlen] of integer;

哨兵        数据域  指针域

1.赛精度加法

 

procedure plus ( a,b:hp; var c:hp);
var i,len:integer;
begin
fillchar(c,sizeof(c),0);
if a[0]>b[0] then len:=a[0] else len:=b[0];
for i:=1 to len do begin
inc(c[i],a[i]+b[i]);
if c[i]>10 then begin dec(c[i],10); inc(c[i+1]); end; {进位}
end;
if c[len+1]>0 then inc(len);
c[0]:=len;
end;{plus}

 

2.强精度减法
procedure substract(a,b:hp;var c:hp);
var i,len:integer;
begin
fillchar(c,sizeof(c),0);
if a[0]>b[0] then len:=a[0] else len:=b[0];
for i:=1 to len do begin
inc(c[i],a[i]-b[i]);
if c[i]<0 then begin inc(c[i],10);dec(c[i+1]); end;
while (len>1) and (c[len]=0) do dec(len);
c[0]:=len;
end;

 

3.高精度就以低精度

例二、插入排序:在一个文书文件被存放的N个人之全名,文本文件的格式为:第一行为N,以下第二顶第N+1行分别是N个人的姓名(姓名不还,由英文字母组成,长度不超越10),请编一个先后,将这些姓名按字典顺序排列。

procedure multiply(a:hp;b:longint;var c:hp);
var i,len:integer;
begin
fillchar(c,sizeof(c),0);
len:=a[0];
for i:=1 to len do begin
inc(c[i],a[i]*b);
inc(c[i+1],(a[i]*b) p 10);
c[i]:=c[i] mod 10;
end;
inc(len);
while (c[len]>=10) do begin {处理高位之进位}
c[len+1]:=c[len] p 10;
c[len]:=c[len] mod 10;
inc(len);
end;
while (len>1) and (c[len]=0) do dec(len); {若未待进位则调整len}
c[0]:=len;
end;{multiply}

 

4.胜过精度就以大精度

分析:(1)排序有多措施,插入排序是里的如出一辙种,其规律同摸扑克牌类似:摸到均等张牌,把它仍大小顺序插入牌中,每一样布置还如此处理,摸了晚,得到的就是同一合以不变应万变的扑克牌。本题可以据此插入排序求解;

procedure high_multiply(a,b:hp; var c:hp}
var i,j,len:integer;
begin
fillchar(c,sizeof(c),0);
for i:=1 to a[0] do
for j:=1 to b[0] do begin
inc(c[i+j-1],a[i]*b[j]);
inc(c[i+j],c[i+j-1] p 10);
c[i+j-1]:=c[i+j-1] mod 10;
end;
len:=a[0]+b[0]+1;
while (len>1) and (c[len]=0) do dec(len);
c[0]:=len;
end;

     
(2)为了减小活动数据的干活,可以使用链式存储结构。每个结点由个别只地面构成,数据域(用来存放姓名)和指针域(用来存放在后继结点的地址)。如图A是以1,3,6,7遵照梯次构成一个线性链表的示意图。这样于斯不变表中插入一个5经常,只需要对指针进行对应地操作即可,如下图B:

5.胜精度除为小精度

          ┌─┬─┐ ┌─┬─┐ ┌─┬─┐ ┌─┬─┐

procedure devide(a:hp;b:longint; var c:hp; var d:longint);
{c:=a p b; d:= a mod b}
var i,len:integer;
begin
fillchar(c,sizeof(c),0);
len:=a[0]; d:=0;
for i:=len downto 1 do begin
d:=d*10+a[i];
c[i]:=d p b;
d:=d mod b;
end;
while (len>1) and (c[len]=0) then dec(len);
c[0]:=len;
end;

  头结点→│1 │ –→ │3 │ –→│6 │ –→ │7 │^ │←尾结点

6.强精度除因强精度

          └─┴─┘ └─┴─┘ └─┴─┘ └─┴─┘

procedure high_devide(a,b:hp; var c,d:hp);
var
i,len:integer;
begin
fillchar(c,sizeof(c),0);
fillchar(d,sizeof(d),0);
len:=a[0];d[0]:=1;
for i:=len downto 1 do begin
multiply(d,10,d);
d[1]:=a[i];
while(compare(d,b)>=0) do {即d>=b}
begin
Subtract(d,b,d);
inc(c[i]);
end;
end;
while(len>1)and(c.s[len]=0) do dec(len);
c.len:=len;
end;

                              图 A          

六、 树的遍历

          ┌─┬─┐ ┌─┬─┐ ┌─┬─┐ ┌─┬─┐

1.已掌握前先后中序求后先后

  头结点→│1 │ –→ │3 │  ││6 │  –→│7 │^ │←尾结点

procedure Solve(pre,mid:string);
var i:integer;
begin
if (pre=””) or (mid=””) then exit;
i:=pos(pre[1],mid);
solve(copy(pre,2,i),copy(mid,1,i-1));
solve(copy(pre,i+1,length(pre)-i),copy(mid,i+1,length(mid)-i));
post:=post+pre[1]; {加上根,递归结束晚post即为晚先后遍历}
end;

          └─┴─┘ └─┴┼┘ └↑┴─┘ └─┴─┘

2.都领略中序后序求前序

                           ↓   ┌┘

procedure Solve(mid,post:string);
var i:integer;
begin
if (mid=””) or (post=””) then exit;
i:=pos(post[length(post)],mid);
pre:=pre+post[length(post)]; {加上根,递归结束后pre即为前序遍历}
solve(copy(mid,1,I-1),copy(post,1,I-1));
solve(copy(mid,I+1,length(mid)-I),copy(post,I,length(post)-i));
end;

                          ┌─┬┼┐

3.曾经掌握前序后序求中序的一致种

                          │5 │  │←插入的结点

function ok(s1,s2:string):boolean;
var i,l:integer; p:boolean;
begin
ok:=true;
l:=length(s1);
for i:=1 to l do begin
p:=false;
for j:=1 to l do
if s1[i]=s2[j] then p:=true;
if not p then begin ok:=false;exit;end;
end;
end;

                          └─┴─┘

procedure solve(pre,post:string);
var i:integer;
begin
if (pre=””) or (post=””) then exit;
i:=0;
repeat
inc(i);
until ok(copy(pre,2,i),copy(post,1,i));
solve(copy(pre,2,i),copy(post,1,i));
midstr:=midstr+pre[1];
solve(copy(pre,i+2,length(pre)-i-1),copy(post,i+1,length(post)-i-1));
end;

                            图 B

七 进制转换

 

1.肆意正整数上制间的互化

解:Pascal程序:

除n取余

Program lx2.14;

2.实频自由正整数上制间的互化
乘n取整

type point=^people;          定义结点类型

3.负数进制:
筹一个次,读入一个十上制数的基数以及一个负进制数的基数,并拿之十迈入制数转换为夫负
进制下之高频:-R∈{-2,-3,-4,….-20}

     people=record

八 全列和整合的变型

       name:string[10];     name–数据域,存放姓名

1.排列的变化:(1..n)
procedure solve(dep:integer);
var
i:integer;
begin
if dep=n+1 then begin writeln(s);exit; end;
for i:=1 to n do
if not used[i] then begin
s:=s+chr(i+ord(”0”));used[i]:=true;
solve(dep+1);
s:=copy(s,1,length(s)-1); used[i]:=false;
end;
end;

       next:point;          next–指针域,存放后继结点的地点

2.重组的变动(1..n遭到甄选k个数的有方案)
procedure solve(dep,pre:integer);
var
i:integer;
begin
if dep=k+1 then begin writeln(s);exit; end;
for i:=1 to n do
if (not used[i]) and (i>pre) then begin
s:=s+chr(i+ord(”0”));used[i]:=true;
solve(dep+1,i);
s:=copy(s,1,length(s)-1); used[i]:=false;
end;
end;

     end;

九.查找算法

var head,p,q1,q2:point;

1.折半找寻

    n,i:integer;

function binsearch(k:keytype):integer;
var low,hig,mid:integer;
begin
low:=1;hig:=n;
mid:=(low+hig) p 2;
while (a[mid].key<>k) and (low<=hig) do begin
if a[mid].key>k then hig:=mid-1
else low:=mid+1;
mid:=(low+hig) p 2;
end;
if low>hig then mid:=0;
binsearch:=mid;
end;

 

2.树形查找

begin

二叉排序树:每个结点的值都大于其左子树任一结点的价值如果小于其右子树任一结点之价。
查找
function treesrh(k:keytype):pointer;
var q:pointer;
begin
q:=root;
while (q<>nil) and (q^.key<>k) do
if k<q^.key then q:=q^.left
else q:=q^.right;
treesrh:=q;
end;

  new(head);head^.next:=nil;  定义头结点,初始链表为空

十、贪心

  write(‘n= ‘);

*会议问题
(1)
n个活动每个移动时有发生一个方始日与一个毕时间,任一随时才一宗活动展开,求满足活动数最多的情。
除掉:按各起运动的完结时间开展排序,排在头里的先期满足。

  readln(n);

(2)会议室空闲时最少。

  for i:=1 to n do

(3)每个客户发出一个愿付的租,求最好充分利润。

    begin

(4)共R间会议室,第i单客户需要以i间会议室,费用一律,求最好老利润。

      new(p);readln(p^.name);p^.next:=nil;

十一、回溯法框架

      if head^.next=nil then head^.next:=p   将P指向的结点插入空链表

  1. n皇后问题

        else

procedure try(i:byte);
var j:byte;
begin
if i=n+1 then begin print;exit;end;
for j:=1 to n do
if a[i] and b[j+i] and c[j-i] then begin
x[i]:=j;
a[j]:=false; b[j+i]:=false; c[j-i]:=false;
try(i+1);
a[j]:=true; b[i+j]:=true; c[j-i]:=true;
end;
end;

          begin

2.Hanoi Tower 汉诺塔

            q1:=head;q2:=q1^.next;

h(n)=2*h(n-1)+1
h(1)=1
初始所有铜片都当a柱上
procedure hanoi(n,a,b,c:byte); {将第n块铜片从a柱通过b柱移到c柱上}
begin
if n=0 then exit;
hanoi(n-1,a,c,b); {将方面的n-1块从a柱通过c柱移到b柱上}
write(n,’moved from’,a,’to’,c);
hanoi(n-1,b,a,c);{ 将b上的n-1块从b柱通过a柱移到c柱上
end;

            while (q2<>nil) and (q2^.name<p^.name) do

开铜片分布在3独支柱上,给得目标柱goal
h[1..3,0..n]存放三只支柱的状态,now与nowp存最特别的不成功的铜片的柱号和号码,h[I,0]满怀第I单支柱上之个数。

              begin q1:=q2;q2:=q1^.next; end;     查找结点p应插入的岗位 

Procedure move(k,goal:integer); {将无限要命莫成就的k移到对象柱goal上}
Begin
If k=0 then exit;
For I:=1 to 3 do
For j:=1 to han[I,0] do
If h[I,j]=k then begin now:=I;nowp:=j; end; {找到k的位置}
If now<>goal then begin {若无更换到对象}
Move(k-1,6-now-goal); {剩下的先移到没有因此之柱上}
Writeln(k moved from now to goal);
H[goal,h[goal,0]+1]:=h[now,nowp]; h[now,nowp]:=0;
Inc(h[goal,0]); dec(h[now,0]);
Move(k-1,goal); {剩下的换到对象及}
End;

            q1^.next:=p;p^.next:=q2;             将p插入q1之后q2之前

十二、DFS框架

          end;  

NOIP2001 数的撤并

     end;

procedure work(dep,pre,s:longint); {入口为work(1,1,n)}
{dep为目前试放的第dep个数,pre为前同一不好试放的屡屡,s为当下剩下可分割的总数}
var j:longint;
begin
if dep=n then begin
if s>=pre then inc(r); exit;
end;
for j:=pre to s p 2 do work(dep+1,j,s-j);
end;
类似:
procedure try(dep:integer);
var i:integer;
begin
if dep=k then begin
if tot>=a[dep-1] then inc(sum);
exit; end;
for i:=a[dep-1] to tot p 2 do begin
a[dep]:=i; dec(tot,i);
try(dep+1);
inc(tot,i);
end;
end;{try}

  writeln;

十三、BFS框架

  p:=head^.next;

IOI94 房间问题
head:=1; tail:=0;
while tail<head do begin
inc(tail);
for k:=1 to n do
if k方向而扩大 then begin
inc(head);
list[head].x:=list[tail].x+dx[k]; {扩展出新结点list[head]}
list[head].y:=list[tail].y+dy[k];
拍卖新结点list[head];
end;
end;

  while p<>nil do        输出

十五、数据结构相关算法

    begin

1.链表底稳定函数

      writeln(p^.name);

loc(I:integer):pointer; {寻找链表中之第I个结点的指针}
procedure loc(L:linklist; I:integer):pointer;
var p:pointer;
j:integer;
begin
p:=L.head; j:=0;
if (I>=1) and (I<=L.len) then
while j<I do begin p:=p^.next; inc(j); end;
loc:=p;
end;

      p:=p^.next;

2.才链表的插入操作

    end;

procedure insert(L:linklist; I:integer; x:datatype);
var p,q:pointer;
begin
p:=loc(L,I);
new(q);
q^.data:=x;
q^.next:=p^.next;
p^.next:=q;
inc(L.len);
end;

  end.

3.特链表的勾操作

 

procedure delete(L:linklist; I:integer);
var p,q:pointer;
begin
p:=loc(L,I-1);
q:=p^.next;
p^.next:=q^.next;
dispose(q);
dec(L.len);
end;

老三、数据结构研究的对象

4.双双链表的插操作(插入新了点q)

   1. 数的逻辑结构(数据里面的涉嫌)。

p:=loc(L,I);
new(q);
q^.data:=x;
q^.pre:=p;
q^.next:=p^.next;
p^.next:=q;
q^.next^.pre:=q;

   2. 数码的物理构造(数据以处理器中的囤积方)。

5.夹链表的去操作

   3. 数目的算法处理(处理不同结构数据的点子)。

p:=loc(L,I); {p为要抹的结点}
p^.pre^.next:=p^.next;
p^.next^.pre:=p^.pre;
dispose(p);

 

季、数据的演算:插入、删除、更新、排序、查找。

 例:删除线性表中所有的X

Program delx;

var

s:array[1..100]of integer;

i,j,n,x:integer;

begin

readln(n);

for i:=1 to n do begin read(s[i]);write(s[i]:5) end;

readln(x);

i:=1;

while i<=n do  if s[i]<>x then i:=i+1

else begin

for j:=i to n-1 do s[j]:=s[j+1];

n:=n-1;

end;

for i:=1 to n do write(s[i],’  ‘);

writeln;writeln(‘n=’,n)

end.

呼吁同学等之所以链表完成

五、并查集:连查集是一样栽树型的数据结构,用于拍卖部分无交集合(Disjoint
Sets)的联合和查询问题。并查集有三独操作:初始化,合并,查询。
    1、并查集的简约实现(见P5)

像,给定集合 S
={1,2,…,7},及等价性条件:1≡2,5≡6,3≡4,1≡4,对集合S作等价类划分如下:首先将S的诸一个因素看成一个等价类。然后依次地处理所被的等价性条件。每次处理一个等价性条件,所获取的附和等价类列表如下:

{1}、{2}、{3}…{7}

1≡2 {1,2}{3}{4}{5}{6}{7};

5≡6 {1,2}{3}{4}{5,6}{7};

3≡4 {1,2}{3,4}{5,6}{7};
   1≡4 {1,2,3,4}{5,6}{7};

说到底所获的集合S的等价类划分也:{1,2,3,4}{5,6}{7}。

例:若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。

规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。

 输入格式 

第一行:三个整数n,m,p,(n<=5000,m<=5000,p<=5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系。

以下m行:每行两个数Mi,Mj,1<=Mi,Mj<=N,表示Ai和Bi具有亲戚关系。

接下来p行:每行两个数Pi,Pj,询问Pi和Pj是否具有亲戚关系。

 输出格式 

P行,每行一个'Yes'或'No'。表示第i个询问的答案为“具有”或“不具有”亲戚关系。

 

program family;

var c:array[0..5000]of longint;

    i,j,m,n,p,x,y,a,b:longint;

function find(x:longint):longint;

  begin

    find:=c[x];

  end;

procedure union(a,b:longint);

  begin

    for i:=1 to n do

    if c[i]=b then c[i]:=a;

  end;

begin

  read(n,m,p);

  for i:= 1 to n do c[i]:=i;

  for j:= 1 to m do

    begin

      read(x,y);

           a:=find(x);

      b:=find(y);

      if a<>b then union(a,b);

    end;

  for i:= 1 to p do

    begin

      read(x,y);

      if c[x]=c[y] then writeln('Yes')

                         else writeln('No');

    end;

end.

 

2、并查集的树型实现(见P5~7)

 

六、哈希表

确立重大字k到囤地址p之间的一个相应关系p=H(k)称为哈希函数,与之对应的表叫哈希表。

1、哈希函数的布局

⑴直接定址法:取关键字或者主要字之某线性函数值作为哈希地址,即:H(k)=k或H(k)=ak+b。

⑵数字分析法:取关键字被遍布于咸匀的多各项,构成哈希地址。

⑶平方取中模仿:取关键字k的平方值的中级几乎员作为哈希地址。

⑷移位法和折叠法:

⑸除留余数法:即 H(k)=k mod p (p为小于哈希表长的尽酷素数)

2、处理闯之法子

⑴开放地方法:由j=H(k)找到地方后,若j位置上已在多少,可用如下方法寻找空位:

              Ri=(H(k)+di)mod m (i=1,2,3,…,m-1) 
(m为哈希表长

              di =1,2,3,…,m-1 (线性探测再散列)

              di
=12,-12,22,-22,32,-32,…,k2(二不成探测再散列)

⑵链地址法:给哈希表中的每个节点增加一个指针字段,用来链接发生冲突的笔录。

3、哈希表的检索

首先计算p0=H(k),若单元p0为空,
则所查元素不存,若单元p0中元素的机要字为k则找到,否则,按解决冲突的方案找来下一个哈希地址pi。

 

1.2 算法:大凡以少数步骤内求解某同题材所下的同样组定义明确的平整。

平、算法的风味

1.  有限性,即排的项数有限,且各一样采取算项都可于少的时间内成功;

2.  显而易见,即行的诸一样起运算都来众所周知的概念,无二义性;

3.  足无输入运算项,但必然要发出口运算项;

4.  可行性,即对随意给定的官的输入还能够博得相应的不错的出口。

其次、算法的表示:自然语言、流程图、N-S结构流程图、伪代码、类Pascal语言

其三、算法的评介:
程序优劣之正规化:正确性、可读性、健壮性、高效性。(运行时掉,占用空间少)

 1、算法的日子复杂度

其后统计法:与机具硬件有关,不可取。
      事前分析法:用程序执行语句次数之主体 T(n)≈
O(nk)即时间复杂度的价格来度量程序的高低。
      ⑴时间复杂度的标价

  例:设同一总长序段如下:            各行语句执行次数

    ① for i:=1 to n do         n+1

② for j:=1 to n do                  n(n+1)

③ x:=x+1                         n*n

 该程序段总的履行语句次数 f ( n ) = 2n2 + 2n +
1,我们以多项式的重点部分2n2概念也顺序的时光复杂度。记否:T(n)≈
O(n) 其中O(n)表示该程序段的流年复杂度的价。

 

⑵时间复杂度的盘算
    例:计算   y = anxn +
an-1xn-1 + … + a1x + a0

  算法一: y:=a[0]

         For  k:=1 to n do

           Begin

              S:=a[k];

              For j:=1 to k do  s:=s*x;

              Y:=y+s;

           End;

           Writeln(‘y=’,y);

计算y共用乘法 1+2+3… +n = 次, 共用加法n次, 时间复杂度为,
阶为O(n2)

    

用算式变为  y=(…( ( an*x + an-1 )*x +
an-2 )*x + … + a1)*x+a0

     算法二: y:=a[n];

              For  k:=n-1 to 0  do y:=y*x + a[k];

              Writeln(‘y=’, y );

计算y共用就法 n次,  共用加法n次,  时间复杂度为2n,   阶为O(n)

 

       ⑶时间复杂度价的可比
       O(1)       问题规模变化时,复杂性变化不怪, 优秀。

       O(n)       问题规模变化是线性的,很好。

       O(n log2n)  任然时一个于好之算法。

       O( nk)      应尽可能的改善,使k 的价值更小更好。

       O(2n)      n较充分时,复杂性会变的异常十分,避免采用。

 

⑷优化时间效率的法门

    1. 尽量在编译时赋值。

  1. 故此高速运算代替慢速运算。

  2. 免重复运算。

  3. 减少,紧索,优化循环。

  4. 减去重复判断。

  5. 尽心尽力采用模块等措施。

 

2、算法的长空复杂度

1.滑坡存储技术

2.原地工作

章:约瑟夫问题 设有n个人数围绕以于一个圆桌周围,现由第s私有开始报数,数到第m个体出列,然后由出列的生一个丁另行开所累,数届第m私家而出列,……,如此重,直到所有人出列为止。输入:n,s,m, 输出:出列顺序

 

program ysfwt;

var

   i,n,k,m,s,w,j :integer;

   p:array[1..100] of integer;

   begin

     repeat readln(n,s,m); until s<=n;

     for i:=1 to n do p[i]:=i;

     k:=s;

     for i:=n downto 2 do    //参加报数的人口由n到2 逐次减1

       begin

         k:=(k+m-1)mod i; 
//k:数组中起列的岗位,m:每次报数m个,i:参加报数的人数

         if k=0 then k:=i;

         w:=p[k];   //保留出列的序号

         if k<i then for j:=k to i-1 do p[j]:=p[j+1]; 
//移动数组,腾出第i各

         p[i]:=w;   // 在原数组中保留出列的序号

       end;

     for i:=n downto 1 do write(n-i+1,’:’,p[i],’ ‘);

     writeln;

   end.

 

齐例被直接动用队列a计算出队顺序就是原地工作

 

3、程序设计被日及上空的转移

 例:编程找来有3个数及7员数着的水仙花数(见P15~16)

program exe1_3_1;  //枚举每个数时都临时计算各位数字之乘方幂。

var

  x,s,e:longint;

  i,j,m,l,d:integer;

  st:string;

begin

  for x:=100 to 9999999 do

    begin

      str(x,st); l:=length(st); s:=0;

      for i:=1 to l do

        begin

          e:=1; val(st[i],m,d);

          for j:=1 to l do e:=e*m;

          s:=s+e;

        end;

      if s=x then writeln(x);

    end;

end.

 

program exe1_3_2;  //先计算0~9各个数字的3~7涂鸦方保存在数组吃,在坐

var                 后底枚举中无时无刻调用

  lists:array[0..9,3..7]of longint;

  x,s:longint;

  i,j,m,l,d:integer;

  st:string;

begin

  for i:=3 to 7 do lists[0,i]:=0;

  for i:=3 to 7 do lists[1,i]:=1;

  for i:=2 to 9 do lists[i,3]:=i*i*i;

  for i:=2 to 9 do

    for j:=4 to 7 do lists[i,j]:=lists[i,j-1]*i;

  for x:=100 to 9999999 do

    begin

      str(x,st); l:=length(st); s:=0;

      for i:=1 to l do

        begin

          val(st[i],m,d);

          s:=s+lists[m,l];

        end;

      if s=x then writeln(x);

    end;

end.

1.3 建数学模型  
一、概述

1.概念:
数学建模是利用数学语言(符号、式子与图像)模拟现实的型。(数学模型揭示了实际上问题最为本质之特色,而算法则是白手起家以数学模型之上,更多考虑模型在微机上哪些促成)

譬如说:洗碗的数学模型呢 x/2+x/3+x/4=65

2.属性:抽象性、高效性、可推广性 (例1-4 p17)

① for i:=1000 to 9999 do
     if (I div 1000=(I div 100)mod 10)and(I mod 10=(I mod 100)div
10)and(sqrt(i)=trunk(sqrt(i)))
② for y:=32 to 99 do begin
                        x:=y*y; b1:=x mod 10; b2:=(x div 10)mod 10;

                     a1:=(x div 100)mod 10; a2:=x div 1000

                     if (b1=b2)and(a1=a2)then write(x)

                   end

3.树数学模型的计和步子

   模型准备 → 建立模型 → 模型求解 → 编程实现

4.数学模型的评说:可靠性(准确地反映出具体)、可解性(由其有的算法所急需的时日跟上空在可接受的界定中)

5.施用举例(例1-5 P18)

针对擅自的x∈(1000,9999),分解x的诸位数字得到a,b,c,d四只数字
范一:for x:=1000 to 9999 do  时间复杂度T(n)=9999-1000+1=9000

          分解x的各位数字,存放到变量a,b,c,d中

     
    Flag:=(10*a+b)<(10*c+d)and((10*a+b)/(10*c+d)=a/d)and(b=c)

          If flag=true then writeln(ab,’/’,cd);

范二: for x=10 to 99 do 
时间复杂度T(n)=90*45=4050,大约下跌1/2

           For y=x+1 to 99 to

             分解分子x的各位数字,存放到变量a,b中

             说分母y的诸位数字,存放到变量c,d中

             If (x/y=a/d)and(b=c) then writeln(x,’/’,y);

型三:for a:=1 to 9 do  时间复杂度T(n)=9*9*9=729,大约下跌8/9

for b:=1 to 9 do

for d:=1 to 9 do

              x=10*a+b;y:=10*b+d  (合成分子x和分母y)

              If x/y=a/d then writeln(x,’/’,y);

1.4  次的调节
先后的左产生个别类 1.语法错误:编译程序可得知(compile)
                 
2.语义谬误:(错误公式、溢起、越界、死循环、程序结构或逻辑出错)
调试程序的点子   1.静态查错:不履行顺序,仅因程序清单和流程图查错
          2.动态查错:在程序执行的经过中找找错误

 

一律、系统的测试工具
  Turbo pascal 含大量之动态调试功能,主要集中在子菜单(Run  Debug 
option 中,见P6图1.2)

 

亚、调试程序的相似经过
    1.调节初始化
    ①安装检查状态:按Ctrl+o+o 将数值越界,堆栈、内存检查如果为on状态

    ②装观察状态:选Debug中的Watch项,在屏幕配开辟观察窗口,选Debug中的add
Watch项,加入如察看的变量。

2.调节方式的挑

  ①单纯步跟综:选Run中的Step over (F8) 一次于执行进程与函数调用。
          选Run中之Trace into(F7) 以同次一行的方式实行顺序。
    ②履到光标所在行:选Run中之Goto cursor (F4)
程序执行到光标所在行暂停。
    ③决点:选Debug / add break point (Ctrl+F8)
将光标所于行设为断点。
        选Debug / breakpoints 可去除断点或设定下一断点之岗位。
  3.预备调试后的程序运行
  也加强运行的频率,在调节完毕晚答应以数值越界、堆栈检查还原为off状态。

 

其三、测试用例的取舍:逻辑覆盖测试的白箱法。
          程序功能测试的暗箱法。

1.白箱法
    ①语句覆盖:用足多之测试用例,使程序中之每个语句都实行同样百分之百,以尽可能地发现错误。

  ②分段覆盖:用足多之测试用例,使程序中的每个分支至少经过平等不行。

  ③准绳覆盖:用足多的测试用例,使每个判定中之每个条件都能够取得两种不同之结果。 

  ④结合条件覆盖:用足多之测试用例,使每个判定中之规则的各种或构成至少出现同等糟。

2.黑箱法
       
①等价分类法:将具备能够输入的数码(有效和无效)划分成几何等价类,每类吃取一组数为测试用例。

②限值分析法:对输入范围之分界情况跟小超出范围的失效情况展开测试。

③错推测法:用有些无限的数据测试,如排序程序可检查表为空、表里只来一个素、所有因素相同、已经平稳等。

3.归纳方针

眼前,没有一样种艺术会单独地出相同效仿“定型”的测试用例,在实质上测试中答应同利用,一般步骤是:首先由黑箱法开始为此相当价格分类、边值分析、错误推测等方法寻找来程序中不备力量要求的地方,然后据此白箱法的支行覆盖、条件覆盖、语句覆盖检测程序中是那些子程序段导致该荒谬,修改后还用黑箱法测试结果,这样循环反复,提高程序的正确率。

练习:1、翻硬币。

      2、删除线性表中所有的x。

      3、并查集的兑现。

      4、约瑟夫问题

第二节指针和动态数据结构

静态数据结构:各变量对应之空中程序运行前早已规定,运行着莫可知更改数据结构    
动态数据结构: 程序在运转时能够根据数量要而扩展或回落

 

2.1指针变量的定义和骨干以

同、指针变量的概念:指针变量是同样种植特别的变量,它是为此来存放在地点(指针)的。

以更直观地亮,我们就此生图来说明

指南针变量p“记忆”了动态变量内存单元地址值,我们称之为p“指向”某内

存单老大。指向用箭头表示

指南针变量是静态的概括变量,但它们跟整型、实型不同,它存放的凡地点,指于除文件外之有平等种多少类,固指针变量应如下说明:

指南针变量说明的相似格式为:
   Var
  指针变量名表:^基类型;
如: var
     p,q: ^integer;

仲、指针变量的以
1.开拓动态存储单元
格式:new(指针变量) 如 new(p)
意义:系统将活动分配一片内存,并拿它的首地址存入指针变量中,也就是是要指针变量指向新生成的动态变量。如
new(p1)
2.刑满释放动态存储单元
格式:dispose(指针变量) 如 dispose(p)
力量: 释放指针所针对的存储单元,使指针变量的价无定义。
3.指针变量的赋值和操作
格式:<指针变量>:=<指针变量> 如 p:=q(特殊情况
p:=nil代表不因为外存储单元)
效能:使p和q同时对q所指向的存储单元。

格式:<指针变量>^:=<指针变量>^ 如p^:=q^
成效:将q所对的存储单元的值存放到p所指向的存储单元中。
4.例:输入两个整数,按自小到深打印出来。(P30~31)

2.2链表
  

链表是动态数据结构的相同种植基本形式。如果我们将指针所依的一个储备单元叫做结点,那么链表就是拿多少个了结点链成了一样差。下面就是一个链表:

每个结点有零星单地方,一个是数据域,一个凡是凭于下一个结点的指针域。最后一个结点的指针域为NIL,NIL表示空指针。
一样、链表的定义
    要定义一个链表,每个结点要定义成记录型,而且内有一个域为指针。
TYPE  
   POINT=^PP;
   PP=RECORD
       DATA:STRING[5];
       LINK:POINT;
       END;
VAR  P1,P2:POINT;
其次、建立链表

 

(1)建立第一个结点
   NEW(P1);
   P1↑.DATA:=D1;
 (2) 建立第二只结点,并把她连着在P1的后面
        NEW(P2);
        P2↑.DATA:=D2;
        P1↑.LINK:=P2;
 (3) 建立第三单结点,并把它连接在P2的后面.
        NEW(P3);
        P3↑.DATA:=D3;
        P2↑.LINK:=P3;
(4) 建立最后一个结点,并把它们连着在P3的后面.
    NEW(P4);
    P4↑.DATA:=D4;
    P4↑.LINK:=NIL;
    P3↑.LINK:=P4;
 

 

 

例1 建立一个生出10独结点的链表,最后输出该链表。
PROGRAM  E1(INPUT,OUTPUT);
TYPE point=^pp;
        pp=record
               data:string[5];
               link:point;
            end;
 VAR
    p1,p2,k:point;
              i:integer;
 BEGIN  {产生新结点P1,作为链表的腔}
   new(p1);
   writeln(‘input data’);
   readln(p1^.data);  
   k:=p1;    {指针K指向链表头}
 {用循环产生9单新结点,每个结点都通在齐一个结点之后}
for i:=1 to 9 do
     begin
          new(p2);
          writeln(‘input data’);
                      readln(p2^.data);
                      p1^.link:=p2;
                      p1:=p2;
    end;
    {给最终一个结点的LINK域赋空值NIL}
     p2^.link:=nil;
    {从链表头开始挨家挨户输出链表中的DATA域}
   while k^.link<>nil do
           begin
                write(k^.data,’->’);
                 k:=k^.link;
             end;
      END.

链表的遍历:出口链表的经过尽管是一个链表的遍历。给来一个链表的头结点,依次输出后面每一个结点的内容,指针依次往后活动的言辞用K:=K↑.LINK 
来落实。
先进先出链表(或称队) 例2  读入一批数量,遇负数时停下,将读入的正数组成先进先出的链表并出口。
  
分析:首先应定义指针类型,结点类型和指针变量,读入第一单价,建立首结点,读入第二只价,判断它们是不是超越零,若是,建立新结点。

 

PROGRAM fifo(input,output);
{建立先进先出链表}
TYPE
 Point=^node;
 Node=RECORD
Data:real;
Link:point
END;
          VAR
           head,last,next:point;
           x:real;
          BEGIN
          {读入第一只价,建立首结点}
           read(x);
       write(x:6:1);
       new(head);
       head^.data:=x;
       last:=head; {读入第二个价}
        read(x);
        write(x:6:1);
        WHILE x>=0 DO
         BEGIN {建立新结点}
         new(next);
         next^.data:=x;  {链接到表尾}
         last^.link:=next; {指针下更换}
        last:=next;      {读入下一个值}
           read(x);
           write(x:6:1)
          END;
         Writeln;    {表尾指针域置NIL}
         Last^.link:=NIL; 
         Next:=head;
         WHILE next<>NIL DO
  BEGIN   {输出链表}
   Write(next^.data:6:1);
   Next:=next^.link
   END;
    Writeln
         END.


先进后出链表(或称栈)
例3读入一批数量,遇负数时停下,将读入的正数组成先进后出的链表并出口。

 

PROGRAM fifo(input,output);
{建立先进后出链表}
TYPE
 point=^node;
 node=RECORD
data:real;
link:point
END;
          VAR
           head,last,next:point;
           x:real;
          BEGIN
          {初始准备}
           next:=NIL;
           read(x);  {读入第一个数}
           write(x:6:1);
           WHILE x>=0 DO
        BEGIN {建立一个初结点}
        new(head);
        head^.data:=x;  {链接到表首}
        head^.link:=next;{指针前移}
        next:=head;      {读入下一个勤}
        read(x);
        write(x:6:1)
END;
          writeln;         {输出链表}
          WHILE next<>NIL DO
BEGIN
  write(next^.data:6:1);
  next:=next^.link
END;
          writeln
       END.

 
 

 

其三、在链表中插入结点
 
1、插入表头   new(q); q^.next:=h; h:=q;
   2、插入表中   new(q); p1^.next:=q; q^.next:=p2;
   3、插入表尾   new(q); p2^.next:=q; q^.next:=nil;

   例1:在一个平稳链表中插入一个新的结点,使

安插后任然有序(应留神表头、表中、表尾的例外处理,见P37)。

  
例2:读入一批数,遇负数时结束,将正数组成有序链表(先念入一个累作为表头,以后读入每个数都调用上例被插入过程,见P38)

季、在链表中删去一个结点

算法分点儿步:①摸索(应考虑头结点、非头结点、没找到三种植情景),

②删除(见P39)

 

五、循环链表

   
将单纯为链表的表尾结点的指针域指向表头,就如尽链表形成一个绕,这种首尾相连的链表称为循环链表
(例:约瑟夫问题 见P41)

 

六、双向链表

而外首尾结点外,每个结点都起指向前驱和晚的点滴单依靠针域,这种链表称为双向链表。(同样也得定义一个循环双向链表)

1、  定义一个双向链表
type

     Pointer=^note;

     Note=record

            Data:integer;

            Llink:pointer;

            Rlink:pointer;

      End;

2、    在双向链表中插一个结点(在p所指向的结点之前插入一个新了点s)
①s^.llink:=p^.llink;  ②s^.rlink:=p;  ③p^.llink^.rlink:=s;  ④p^.llink:=s;

3、  在双向链表中去一个结点(删除p所指向的结点)
①p^.llink^.rlink:=p^.rlink;  ②p^.rlink^.llink:=p^.llink;  ③dispose(p);

练习:1、建立一个先进先出链表并出口。

      2、建立一个先进后出链表并出口。

      3、编写一个简的中学新生入校登记表处理程序。

      4、链表原地逆置。

      5、删除链表中极深及极小的节点。

      6、双向链表交换相邻的简单单节点。

      7、约瑟夫问题(链表完成)。

老三节文件

Pascal中的文件发出三种植档次,文本文件、随机文件及无类型文件,NOI竞赛被还采取文本文件形式。

3.1文件文件的逻辑组织

同等、文件名   格式: 主文件称(最多8个字符) .
扩展名(最多3单字符,可以无)

文件称受到运用的字符不分轻重缓急写,一律作大写,如 ab.dat  AB.DAT
都看作AB.DAT。

亚、文本文件的逻辑组成 

文件文件是同种实施结构的字符文件,数据元素没有统一的长短,(由0个跟多个字符构成)元素中下回车符(ord(CR)=13)或回车/换行符(ord(CR/LF)=13/10)分隔,文本文件被的一个数量称一执。

老三、文件被的指针

1、打开一个文书,文件指针指为第一个数据的第一单字符

2、文本文件是均等种顺序存取文件

3、对于与一个文件文件未能够以既读而写

3.2文书文件之基本操作

平、定义   格式: var  f1,f2: text; 
用专业的输入(input)、输出文件(output)文件时无需变量说明。

第二、文本文件的操作步骤:
打开文件(首先用assign连接外部和其间文件,然后用rewrite、reset或append等措施打开文件)→
读/写文件(用read读取或因故 write 写副数据)→ 关闭文件(用close关闭文件)

  1、打开一个当磁盘上业已在的文书,从文本中读取数据
assign(input, ‘li01.in’);  reset(input);  read(x);  close(input);  

  2、打开一个初文件,向文件中形容副数据

     assign(output, ‘li01.out’);  rewrite(output);  write(x); 
close(output);

  3、打开一个业已在的文书,并往文件末尾追加数据

     assign(output, ‘li01.out’);  append(output);  write(x); 
close(output);

中间x可以是字符、整型、实型、字符串,系统以机关从文本文件中读取一个要么多个字符,并将那个更换为变量所求的类型。

老三、文件操作的函数

   1、eoln(文件变量)
若文件指针指向文件执行了或文件了符,则赶回true,否则回false。

2、eof(文件变量) 若文件指针指向文件了符,则赶回true,否则回false。

3、seekeoln(文件变量)
与eoln相似,只是文件指针会自动跳了ASCII码0-32的控制符和空格。

4、seekeof(文件变量)
与eof相似,只是文件指针会活动跳了ASCII码0-32之控制符和空格。
习:1、建立一个因为“#”结束的磁盘文件。

2、统计数字 (要求用链表、数组两种植艺术成功)

某次科研调查时获得了n个自然数,每个数均不跳1500000000(1.5*109)。已知道不相同的一再不越10000单,现在得统计这些自然数各自出现的次数,并遵照自然数从小至那个之相继输出统计结果。

【输入】

    输入文件count.in包含n+1行;

    第一尽是整数n,表示自然数的个数;

    第2~n+1每行一个自然数。

【输出】

   
输出文件count.out包含m行(m为n个自然数中不等同数的个数),按照自然数从小至异常的各个输出。每行输出两独整数,分别是自然数和该数出现的次数,其间用一个空格隔开。

 

【输入输出样例】

count.in  

8

2

4

2

4

5

100

2

100

 

count.out

2 3

4 2

5 1

100 2

 

program ex2_b1;(链表解法)

type

  pointer=^rec;

  rec=record

        data,count:longint;

        next:pointer;

      end;

var

  k,n,i:longint;

  s,h:pointer;

procedure search(x:longint);

var q,p1,p2:pointer;

begin

  new(q); q^.data:=x; inc(q^.count);

  if x<h^.data then begin q^.next:=h;h:=q;end

    else begin

         p2:=h;

         while (x>p2^.data)and(p2^.next<>nil) do begin
p1:=p2;p2:=p2^.next; end;

         if p2^.data=x then p2^.count:=p2^.count+1

           else if x<p2^.data then begin  p1^.next:=q; q^.next:=p2;
end

                    else begin p2^.next:=q; q^.next:=nil end

         end;

end;

procedure printlist(p:pointer);

begin

  while p<>nil do begin writeln(p^.data,’  ‘,p^.count);p:=p^.next;
end;

end;

 

begin

  assign(input,’count3.in’); reset(input);

  assign(output,’count.out’); rewrite(output);

  readln(n);

  new(h);readln(h^.data);h^.count:=1;h^.next:=nil;

  for i:=1 to n-1 do begin readln(k);search(k); end;

  printlist(h);

  close(input);close(output);

end.

 

program lx212;(数组解法)

       var a:array[1..200001] of longint;
                    i,j,k,m,n:longint;
           procedure qsort(s,t:longint);
           var i,j,mid,temp:longint;
            begin
               i:=s;j:=t;mid:=a[(s+t) div 2];
               while i<=j do
                   begin
                      while a[i]<mid do inc(i);
                      while a[j]>mid do dec(j);
                      if i<=j then
                          begin
                            
 temp:=a[i];a[i]:=a[j];a[j]:=temp;
                               inc(i);dec(j);
                          end;
                  end;
             if i<t then qsort(i,t);
             if j>s then qsort(s,j);
          end;
          begin

         assign(input,’count.in’);
              reset(input);
              assign(output,’count.out’);
              rewrite(output);
              readln(n);
              for i:=1 to n do readln(a[i]);
              qsort(1,n);
              a[n+1]:=maxlongint;
              k:=1;
              for i:=2 to n+1 do
              if a[i]<>a[i-1] then 
begin writeln(a[i-1],’ ‘,k); k:=1;end
                                   else k:=k+1; 

             close(input);
             close(output);
          end.

 

第四章 

培植是均等种关键之非线性数据结构,直观地圈,它是数额元素(在培训被叫结点)按分支关系组织起的构造,很形象自然界中之栽培那样。树结构在成立世界中广大存在,如人类社会的族谱和各种社会团体机关都可用树形象代表。树于微机领域中为抱广泛应用,如以编译源程序如下时,可用树表示源源程序如下的语法结构。又使以数据库系统被,树型结构也是信息之根本组织形式之一。一切有层次关系的题目都可用树来描述。

4.1基本概念
 树结构的风味是:它的诸一个结点都得来不止一个一直后继,除根结点外的富有结点都发出且只有发一个直接前趋。

  1. 概念:一蔸树是出于n(n>0)个元素做的简单集合,其中:

(1)每个元素称为结点(node);

(2)有一个特定的结点,称为根结点或树根(root);

(3)除根结点外,其余结点能分开成m(m>=0)个互不相交的片集合
T0,T1,T2,……Tm-1

里头的每个子集又还是平等株树,这些聚集称为这株树的子树。

正如图是千篇一律株典型的栽培:

  1. 树之代表

  ①广义表表示拟:(A(B(E(K,L),F),C(G),D(H(M),I,J)))

②树形表示拟:
       

  1. 至于术语   

①结点名称——根、支结点、叶子。

②结点的关系——前缀(双亲)、后继(孩子)、兄弟(同一层上下的子女)。

③结点底层次——根啊率先重叠,它的男女呢次叠……。

④培养之深浅——组成该树各结点的不过特别层次,如齐图,其深度也4。

⑤养的过——也就凡是开间,简单地游说,就是结点的分支数。以结合该树各结点中极特别之度当作该树的过,如达到图的扶植,其度为3;树中度为零星底结点称为叶结点或极端结点。

⑥子树——树的如出一辙片段称作原树的子树。

⑦林——指多少蔸互不相交的塑造的聚集,如达到图,去丢根结点A,其原来的三棵子树T1、T2、T3的集{T1,T2,T3}就也丛林。

⑧来序树——指树中同层结点从左到右有次序排列,它们之间的次第不能够换,这样的树称为有序树,否则称为无序树。

 

4.2 二叉树

1.
定义:二叉树是结点的点滴集合,这个集或是空的,或是由一个根结点和少数棵互不相交的称左子树和右子树的二叉树组成。

 

  1. 二叉树的五栽基本造型。

 

(a)    
空二叉树;(b)只发一个结点的二叉树;(c)只发生左子树的二叉树;(d)只发生右子树的二叉树;(e)左右全然的二叉树。

 

  3. 二叉树的少数只突出形态:
  (1)完全二叉树——只有极端下的片叠结点度小于2,并且最好下面一重合的结点都集中在该层最左边的多少职务的二叉树;
  (2)满二叉树——除了叶结点外每一个结点都起左右子女且叶结点都地处最底部的二叉树,。

   

                                                                 

 

                                                

 

全二叉树                                       满二叉树

 

 4. 二叉树的重要性性能

(1) 二叉树的底i层上最为多只发生只结点()。

证明:当 i=1 时,=  20  =1 眼看起;

要是第 i=k层新普金娱乐时命题成立,即第k重叠及极度多发生2k-1 个结点。

当i=k+1时,由于第k层的2k-1
独结点每个最多有2个子结点,故最多来 2*2k-1
=2(k+1)-1个结点 。

(2) 深度为 k的二叉树及多生 2k–1
个结点(k>=1),最少有k个结点。

即:1+2+4+8+……+2k-1  =  

(3)对于自由一株二交叉树,如果那个叶结点数也n0,而度数为2底结点总数也n2,则n0=n2+1;

征:假设ni(i=0、1、2),为度是i的结点数,即:n= n0+ n1+ n2

要是 B为二叉树的前驱个数,则B=n-1
②(二叉树只有干净没有前人),所有这些前驱同时还要是过为1暨2的结点的继,故B=
n1+2*n2,③

由③代②得:n= n1+2*n2+1。

由④代①得:n1+2*n2+1 = n0+ n1+ n2  即:n0=n2+1

  

 5. 树或森林转换为二叉树

  ① 普通树 → 二叉树  方法: 左链联孩子,右链联兄弟

   例:

  

                                           

 

② 森林 → 二叉树  方法:
将森林每颗树的根视为小兄弟,以第一株树之根本啊二叉树的根,左链联孩子,右链联兄弟之不二法门易即可。

     例:

   由于树和林可惠及唯一的变成二叉树,故以后主要讨论二叉树。

 

 

4.3  树的囤结构(顺序存储结构和链表存储结构)

4.3.1二叉树的仓储结构

 1. 顺序存储结构(满二叉树,完全二叉树一般下存顺序储结构)

Const  m= 树被结点树的上限;

Type  node= record

      Data :datatype;

      Prt ,lch, rch : 0..m;

      End;

Treetype = array[1..m] of node;

Var tree : treetype;

条例:采用数组tree 存储满二叉树

 

data

ptr

lch

rch

1

A

0

2

3

2

B

1

4

5

3

C

1

6

7

4

D

2

0

0

5

E

2

0

0

6

F

3

0

0

7

G

0

0

0

                              

 

 

 

 

 

 

 

 

2. 链式存储结构(一般二叉树通常以链式存储结构)

言语描述:                                    结点结构:

type tree=^node;                               

    node=record

      data:char;

      lchild,rchild:tree

    end;

var bt:tree;

条例:采用链表存储二叉树

 

 

 

 

 

 

 

 

4.3.2培训的储存结构

(1)顺序存储方式

           Const

             n=树的度;

             m=结点数的上限;             

type node=record

                      data:datatype

                      child:array[1..n] of integer;

                     end;        

             var  tree:array[1..m] of  node;

 (2) 链表存储方

Const

             n=树的度;
      type  btree=^node;

                   node=record

                       data:datatye;

                       next:array[1..n] of btree;

                   end;

          var  root: btree

n度数之结点结构为 

data

Child1

Child2

……

childn

 

4.4塑造的遍历

平、二叉树的遍历


遍历:就是比照自然的规则和一一走遍二叉树的所有结点,使各国一个结点都于聘同蹩脚,而且只有于访问同一涂鸦。由于二叉树是非线性结构,因此,树之遍历实质上是将二叉树的依次结点转换成为一个线性序列来代表。

⑵ 遍历的法门:设 L:遍历左子树

R:遍历右子树

D:访问根结点

尽管备可能的遍历方式也LDR,LRD,RDL,RLD, DLR, DRL

万一考虑优先左后右边则法吧:DLR(前序遍历),LDR(中序遍历),LRD
(后先后遍历)。

1、前序遍历的操作定义如下:                         

苟二叉树为空,则空操作,否则

① 拜根结点

② 先先后遍历左子树

③ 先先后遍历右子树

优先先后遍历右图结果吧:124753689

2、中序遍历的操作定义如下:

只要二叉树为空,则空操作,否则

① 中先后遍历左子树

② 访问根结点

③ 中先后全勤历右子树

中序遍历右图结果吗:742513869

3、后序遍历的操作定义如下:

假定二叉树为空,则空操作,否则

① 后先后遍历左子树

② 后先后整个历右子树

③ 访问根结点

后先后遍历右图结果吗:745289631

 

练习1:上面的希冀表示的二叉树的前序遍历序列:______________________
中先后遍历序列:____________________
后上遍历序列:______________________ 。

打彻底出发,逆时针外像绕行全树,按第一次经过的时空次班出各个结点即为前序列表、按叶结点第一破通过时列出,内部结点第二糟通过时列出就为受列表、按最终一不好通过的次序列表即为后序列表。

 

练习2:在磁盘的目结构中,我们以和某子目录有关联的目录数称为度。例如下图:

 

欠图表达了A盘的目结构:Dl,Dll_…D2备代表子目录的名字.在这边,根目录的过为2。Dl子目录的渡过也2,D1l子目录的渡过为3,
D12,D2,Dlll,D112,D113底度皆为0。若未考查虑子目录的名字.则只是粗略的图示为如下的树结构:若知道一个磁盘的目结构中.度为2的子目录有2度为3之子目录有l个,度也4底子目录有3个。

请问:度为1之子目录共有几只。

 

练习3:设M叉树采用列表法表示,即每棵子树对应一个列表,列表的布局也:子树根结点的值部分(设为一个字符)和用“()”括起来的各子树的列表(如发子树的话),各子列表问用“,”分隔。例如下面的三叉树可用列表a(b(c,d),e,f(g,h,i))表示。

 

描绘起右图的三叉树用列表形式表示的结果:________________________________________。

 

⑶尽历算法:

① 链表算法:

procedure preorder(bt:tree);{先先后遍历根结点为 bt 的二叉树的递归算法}

begin

  if bt<>nil then begin

write(bt^.data);

preorder(bt^.lchild);

preorder(bt^.rchild);

               end;

end;

② 数组算法:

procedure preorder(i:integer);

begin

  if i<>0 then begin

write(tree[i].data);

preorder(tree[i].lchild);

preorder(tree[i].rchild);

               end;

end;

世家颇容易就可改写出中序和后序遍历的递归过程。当然,我们还足以拿递归过程改化用栈实现的非递归过程,以先行先后遍历为例,其它的预留作者就。

Procedure inorder(bt:tree);      {先先后遍历bt所依靠的二叉树}

Var  stack:array[1..n] of tree;

Top:integer;   P:tree;

begin

top:=0;

While not ((bt=nil)and(top=0)) do

Begin

          While bt<>nil do begin 

Write(bt^.data);

Top:=top+1;

Stack[top]:=bt^.rchild

                           bt:=bt^.lchild;

                         end;

          If top<>0 then begin

          b:=stack[top];

top:=top-1;

       End;

End;

End;

 

亚、二叉树的别样要操作:

(1)、建立平等棵二叉树

Procedure pre_crt(var bt:tree);{按优先先后次序输入二叉树被结点的价值,生成

begin                       二叉树的单链表存储结构,bt
为对根结点的指针,’’表示空树}

  Read(ch);

  If ch=’.’ then bt:=nil

  Else begin

         New(bt);                  {建根结点}

         Bt^.data:=ch;

         Pre_crt(bt^.lchild);     {建左子树}

         Pre_crt(bt^.rchild);     {建右子树}

       End;

End;

 

(2)、删除二叉树

Procedure dis(var bt:tree);  {删除二叉树}

Begin

  If bt<>nil then begin

Dis(bt^.lchild);         {删左子树}

Dis(bt^.rchild);         {删右子树}

Dispose(bt);             {释放父结点}

               End;

End;

(3)、插入一个结点到二叉树被

Procedure insert(var bt:tree;n:integer);  {插入一个结点到二叉树被}

Begin

  If bt=nil then begin

new(bt); 

bt^.data:=n; 

bt^.lchild:=nil;

bt^.rchild:=nil;

              End

           Else  if n<bt^.data then insert(bt^.lchild,n)

                             else if n>bt^.data then
insert(bt^.rchild,n); 

End;

(4)、在二叉树被找寻一个屡次,找到归该结点,否则回 nil

Function find(bt:tree;n:integer):tree;{在二叉树被搜索一个屡,

Begin                               找到归该结点,否则回 nil }

  if bt=nil then find:=nil

         else if n<bt^.data then find(bt^.lchild,n)

else if n>bt^.data then find(bt^.rchild,n)

                                         else find:=bt;

end;

(5)、用嵌套括号表示拟输出二叉树

Procedure print(bt:tree);  {用嵌套括号表示拟输出二叉树}

Begin

  If bt<>nil  then  begin

Write(bt^.data);

If (bt^.lchild<>nil)or(bt^.rchild<>nil)  then 

                         Begin

                            Write(‘(’);

                            Print(bt^.lchild);

                            If bt^.rchild<>nil then write(‘,’);

                            Print(bt^.rchild);

                            Write(‘)’);

                         End;

                  End;

End;

 

 

规章:输入一粒二交树,分别出口前序、中序、后序遍历的结果。

一经:二叉树                              应以键盘输入:
AB.C.D..EF..GH..IJ…

 

 

 

 

参照程序:program lx61(input,output);{指针类型}

type

  tpointer=^node;

  node=record

        lch,rch:tpointer;

        data:char

        end;

var

  root:tpointer;

  ch:char;

  procedure preorder(p:tpointer);

   begin

     if p<>nil then

       begin write(p^.data);preorder(p^.lch); preorder(p^.rch);end;

   end;

  procedure inorder(p:tpointer);

   begin

     if p<>nil then

       begin inorder(p^.lch);write(p^.data);inorder(p^.rch);end;

   end;

   procedure postorder(p:tpointer);

   begin

     if p<>nil then

       begin postorder(p^.lch); postorder(p^.rch);write(p^.data); end;

   end;

  procedure create(var p:tpointer);

   begin

     read(ch);

     if ch<> ‘.’ then

       begin new(p);p^.data:=ch;create(p^.lch);create(p^.rch) end

      else p:=nil

   end;

begin

    write(‘input node=  ‘);create(root);

    preorder(root);writeln;inorder(root);writeln;postorder(root);writeln

end.

 

program lx61;  {数组类型}                                          

tree[i].data

tree[i].lch

tree[i].rch

A

2

3

B

0

4

E

5

6

C

0

7

F

0

0

G

8

9

D

0

0

H

0

0

I

10

0

J

0

0

 

const m=100;

type node=record

          data:char;

          lch,rch:0..m;

          end;

var tree:array[1..m]of node;

    n,i,j:1..m;

procedure preorder(i:integer);

  begin

  if i<>0 then

   begin
write(tree[i].data:4);preorder(tree[i].lch);preorder(tree[i].rch)
end;

  end;

procedure inorder(i:integer);

  begin

  if i<>0 then

   begin
inorder(tree[i].lch);write(tree[i].data:4);inorder(tree[i].rch)
end;

  end;

procedure postorder(i:integer);

  begin

  if i<>0 then

   begin
postorder(tree[i].lch);postorder(tree[i].rch);write(tree[i].data:4)
end;

  end;

begin

  readln(n);

  for i:=1 to n do

    begin

      read(tree[i].data);

      read(tree[i].lch);

      readln(tree[i].rch);

    end;

  preorder(1);writeln;inorder(1);writeln;postorder(1);writeln;

end.

 

 

老三、普通有序树的别一样栽遍历方法

   先根遍历:转化为对应之二叉树后由前先后遍历实现。

             ABEKLFCGDHIJ

   后彻底遍历:转化为相应的二叉树后由于中序遍历实现。

             KLEFRGCHIJDA

 

规章:P83 输入一粒普通有序树,输出该树的先根次序和后根本不行序。  

参考程序:program lx83;

 const m=100;

 type

     node=record

          data:char;

          prt,lch,rch:1..m;

          end;

var tree:array[1..m]of node;

    i,j,p,n:1..m;

procedure preorder(i:integer);

  begin

    if i<>0 then  begin

                    write(tree[i].data:3);

                    preorder(tree[i].lch);

                    preorder(tree[i].rch);

                  end;

  end;

procedure inorder(i:integer);

  begin

    if i<>0 then  begin

                    inorder(tree[i].lch);

                    write(tree[i].data:3);

                    inorder(tree[i].rch);

                  end;

  end;

begin

  fillchar(tree,sizeof(tree),0);

  readln(n);

  for i:=1 to n do

    begin

      read(tree[i].data);

      read(j);

      if j<>0 then begin

                     tree[i].lch:=j;tree[j].prt:=i;

                     p:=j;

                     repeat

                       read(j);

                       if j<>0 then begin

                                      tree[p].rch:=j;tree[j].prt:=p;

                                      p:=j;

                                    end;

                      until j=0;

                   end;

      readln;

    end;

  preorder(1);writeln;inorder(1);

end.

 

季、 由二叉树的片种植遍历顺序确定树结构

敲定:已解前先后序列及中序序列可以确定出二叉树;

曾了解被先后序列以及后序序列也得以规定出二叉树;

只是,已解前先后序列及后序序列却无得以确定出二叉树;为什么?举个
3单结点的反例。

比如说:已知道结点的前序序列为 ABCDEFG,中序序列为
CBEDAFG。构造出二叉树。过程呈现下图:

 

规章:输入二叉树的前序与中序,输出二叉树的后序。

参照程序:

program lx89;

var c1,c2:string;

procedure solve2(s1,s2:string);

var k:integer;

  begin

    k:=pos(s2[1],s1);

    if k>1 then solve2(copy(s1,1,k-1),copy(s2,2,k));

    if k<length(s1) then
solve2(copy(s1,k+1,length(s1)-k),copy(s2,k+1,length(s2)-k));

    write(s2[1]);

  end;

begin

  write(‘input inorder=’);  readln(c1);

  write(‘input preorder=’);  readln(c2);

  solve2(c1,c2);

end.

 

条例:输入二叉树的中序与后序,输出二叉树的前序。

参考程序:

program lx88;

var c1,c2:string;

procedure solve(s1,s2:string);

  var k:integer;

  begin

    if length(s2)=1 then write(s2)

      else begin

             k:=pos(s2[length(s2)],s1);

             write(s1[k]);

             if k>1 then solve(copy(s1,1,k-1),copy(s2,1,k-1));

             if k<length(s1) then
solve(copy(s1,k+1,length(s1)-k),copy(s2,k,length(s2)-k));

           end;

  end;

begin

  write(‘input inorder=’);  readln(c1);

  write(‘input postorder=’);  readln(c2);

  solve(c1,c2);

end.

 

4.5 二叉树的要紧应用

(1)二叉排序树

①定义:二叉排序树是空树或有所以下性质:

        若根结点的左子树不拖欠,则左子树的有所结点值都低于根结点值。

        若根结点的右子树不空,则右子树的兼具结点值均大于根结点值。

        根结点的左右子树啊分头吗二叉排序树。

②采取:中序遍历二叉排序树,即可顺序输出各结点。

   例:输入 n (1≤ n ≤100)

            a1, a2, …. An

       输出: 排序后底结果

program lx91;

const m=1000;

type benode=record     {用于存储树的构造}

            data:integer;

            lch,rch:1..m;

            end;

 var b:array[1..m]of benode;

     p,n,i:1..m;   a:array[1..m]of integer;  {用于保存输入的n个数}

 procedure createtree;

   begin

     fillchar(b,sizeof(b),0);

     b[1].data:=a[1];

     for i:=2 to n do

       begin

         b[i].data:=a[i]; p:=1;

         while true do

         begin

          if a[i]<b[p].data then

            if b[p].lch<>0 then p:=b[p].lch

               else begin b[p].lch:=i; break; end

            else if b[p].rch<>0 then p:=b[p].rch

                    else begin b[p].rch:=i; break end;

         end;

       end;

   end;

 procedure inorder(i:integer);

   begin

     if i<>0 then begin

                    inorder(b[i].lch);

                    write(b[i].data:5);

                    inorder(b[i].rch);

                  end;

  end;

 begin

   write(‘n= ‘);readln(n);

   write(‘a[i]= ‘); for i:=1 to n do read(a[i]); writeln;

   createtree;

   inorder(1);

 end.

组织二叉解序树的平分时间复杂度为(n long
2N),优于选择排序和冒泡排序算法的(n2

 

(2)最出彩二立交树

①定义:在装有n个带权叶子结点的二叉树中,使有叶子结点的带权路径长度的同为极端小的二叉树称为最小二叉树(或哈夫曼树)。  
即:最小二叉树要 L =达到极端小。

( 其中Wk 表示第k单叶结点的权值,P
k表示第个k叶结点的路途径长)

章:以下四棵二叉树中,叶结点为A、B、C、D、E ,权值分别吗7、5、2、4、6。

            

L=3 (7+5)+2(2+4+6)=60   L=4(4+2)+3*5+2*6+7=58 
L=7+2*5+3*2+4*5+6*5=63  L=2(7+5+6)+3(2+4)=54

 

②不过美妙二叉树的构造方法:将n个结点看在是n个二叉树的到底,则取森林 F={T1,
T2, ….Tn}

                       
在F中取出权值最小的简单株树合并成新培育,其根值为少棵子树根之和。

                        用新培育代替原先的个别蔸树构成新的林。

                        重复以上两步,直到森林合并成一发树了。

            

         

规章:全校学生的成绩由百分制转换为五相当于分制,在五个等级达到的分布不都匀,分布规律而下表:

遍布范围:    0~59     60~69     70~79     80~89     90~100

分布情况%:    5        15        35        30        15

假如叫出sum(1≤sum≤100000)个学生的百分制成绩,将她转换成五分制成绩,至少要通过多少坏比,其中每个等次等成绩的足足比较粗坏。

输入:sum

      w1, w2, w3, w4, w5 (五独号的实绩的分布规律)

出口:最少比较次数

       5只整数,分别吗每个等不良成绩的足足比较次数。

参照程序

program lx95;

const n=5;

      m=2*n-1;

type

  node=record

       data:integer;

       prt,lch,rch,lth:0..m;

       end;

wtype=array[1..n]of integer;

treetype=array[1..m]of node;

var tree:treetype;

    w:wtype;

    bt,m1,i,j,k,p,sum:integer;

procedure hufm(w:wtype;var tree:treetype;var bt:integer);

  function min(h:integer):integer;

    var i:integer;

    begin

      m1:=maxint;

      for p:=1 to h do

        if (tree[p].prt=0)and(m1>tree[p].data)

          then begin i:=p;m1:=tree[p].data;end;

      min:=i;

    end;

  begin

    fillchar(tree,sizeof(tree),0);

    for i:=1 to n do tree[i].data:=w[i];

    for k:=n+1 to m do begin

                         i:=min(k-1);tree[i].prt:=k;tree[k].lch:=i;

                         j:=min(k-1);tree[j].prt:=k;tree[k].rch:=j;

                         tree[k].data:=tree[i].data+tree[j].data;

                       end;

    bt:=m;

  end;

procedure ht(t:integer);

  begin

    if t=m then tree[t].lth:=0 else
tree[t].lth:=tree[tree[t].prt].lth+1;

    if tree[t].lch<>0 then begin
ht(tree[t].lch);ht(tree[t].rch) end;

  end;

begin

  readln(sum);

  for i:=1 to 5 do read(w[i]);

  hufm(w,tree,bt);

  ht(bt);

  writeln(sum*tree[bt].data);

  for i:=1 to 5 do write(sum*tree[i].lth*tree[i].data:7);

end.

第五章图

5.1 概念
1、定义:图大凡出于顶点V底汇和边E的联谊组成的第二首先组记G=(V,E)

生图是一致无向图(顶点的左右相继不限)

 

                  图1

V={V1,V2,V3,V4,V5}

 E={(V1,V2),(V2,V3),(V3,V4),(V4,V5),(V5,V1),(V2,V5),(V4,V1)}

下图是平等有向图(顶点分先后顺序)

 

V={V1,V2,V3,V4}

E={<V1,V2>,<V2,V4>,<V1,V3>,<V3,V4>,<V4,V1>}

2、完全图(每一样对不同的顶点都起同一条边相连,n个顶点的了图共有n(n-1)/2条边)
3、顶点的度:与极端关联的底限的数量,有向图中等于该终端的入度与出度之与。
入度——以该终端为极的边的数码及
出度——以该终端为起点的尽头的多寡及

 度数也奇数的极端叫做奇点,度数为偶数的点叫做偶点。
[定理1]
图G中拥有终端的度数之与齐边数的2倍增。因为计算顶点的度数时。每条边都就此到2次等。
[定理2] 任意一个图定有奇迹数单奇点。

 

4、路径和连通集
    在图G=(V,E)中,如果对结点a,b,存在满足下述条件的结点序列x1……xk(k>1)
        ⑴ x1=a,xk=b
        ⑵ (xi,xi+1)∈E         i=1¨k-1
尽管如此称结点序列x1=a,x2,…,xk=b为结点a到结点b的均等长长的路径,而路上的数目k-1称为该路线的长短,并遂结点集合{x1,…,xk}为搭集。

5、简单路径和回路
如同长达路子上的结点除起点x1和终点xk可以同样外,其它结点均未一致,则称此路为同样漫长简单路径。上图1丁v1→v2→v3是如出一辙漫漫简单路径,v1→v2→v5→v1→v4请勿是简简单单路径。x1=xk之简便路径称为回路(也称之为环)。例如上图2面临,v1→v2→v4→v1吧同一长达回路。

6、有根图
当一个生往图或凭为图备受,若有一个结点w,它和其它结点都是属的,则称这个图为发出根图,结点w即为其的根本。上图1啊有根图,v1、v2、v3、v4都好用作根本。

7、连通图和最好大连通子图
对无论向图而言,若其中管两独结点之间的交接,则称该图为连图。一个无向图的连通分支定义也这图的最好大连通子图。上图(a)所著之希冀是联网的,它的最大连通子图就是为那个自。

8、强连通图和高连通分支
只要于发生向图的擅自两独结点vi、vj间(vi≠vj),都发平等长条由vi到vj的发生向路,同时还时有发生同漫长由vj到vi的发出于路,则称该起向图是强连通的。有往图中强连通的无限充分子图称为该图的过人连通分支。 

5.2贪图的存储

1.邻接矩阵

        1(或权值)   表示 顶点i和顶点j有边(i和j的路程)

A(i,j)={

        0 表示顶点i和终极j无边

  如图1的矩阵表示也

 

2.邻接表

  数组方法:

极端      相邻顶点       邻接顶点数

 v[i]        d[i,j]             c[i]

1

 

2

4

5

 

 

3

2

 

1

3

5

 

 

3

3

 

2

4

 

 

 

2

4

 

1  

3

5

 

 

3

5

 

1

2

4

 

 

3

链表方法:

1

–>

2

–>

4

–>

5

^

2

–>

1

–>

3

–>

5

^

3

–>

2

–>

4

^

 

 

4

–>

1  

–>

3

–>

5

^

5

–>

1

–>

2

–>

4

^

 

3.边目录

如图2

起点

1

1

2

3

4

终点

2

3

4

4

1

长度

 

 

 

 

 

  6.3贪图的遍历
1.深优先遍历

  遍历算法:

 1)从某个平届点出发开始走访,被聘的终点作相应的符号,输出访问顶点号.

  2)从让拜的终端出发,搜索以及拖欠终端有边的涉的有不给访问的邻接点

又起该邻接点出发进一步摸索以及该终端有边的涉的有不吃访问的邻接点,直到一切接点访问结束毕.如图1于V1开始之深浅优先遍历序列为V1,V2,V3,V4,V5。图2自V1开始的深度优先遍历序列为V1,V2,V4,V3。

算法过程:

procedure shendu(i);

begin

 write(i);

 v[i]:=true;

 for j:=1 to n do

  if (a[i,j]=1) and not(v[j]) then shendu(j);

end;

2.广度先期遍历

遍历算法:

1)从某个顶点出发开始走访,被访问的终点作相应的记,并出口访问顶点号;

2)从为聘的巅峰出发,依次搜索和该终端有边的涉及的享有非让访的邻接点,并作相应的标志。

3)再逐一根据2)中负有被访的邻接点,访问同这些邻接点相关的装有未为看的邻接点,直到所有终端被聘了。如图3的广度优先遍历序列为C1,C2,C3,C4,C5,C6。

算法过程:

procedure guangdu(i);

 begin

  write(i);

  v[i]:=true;

  i进队;

  repeat

   队首元素出队设为k

   for j:=1 to n do

    if (a[k,j]=1) and (not v[j]) then

     begin

      write(j);

      v[j]:=true;

      j进队;

     end;

  until 队列q为空;

6.3 图的采用

例1:有A,B,C,D,E
5本书,要分给张、王、刘、赵、钱5个同学,每人仅选取同仍。每人用爱的书填写下表,输出每人都满意的分书方案。

 

A

B

C

D

E

 

 

1

1

 

1

1

 

 

1

 

1

1

 

 

 

 

 

1

 

 

1

 

 

1

因而递归方式程序如下:

program allotbook;
 type five=1..5;
 const like:array[five,five] of 0..1=
  ((0,0,1,1,0),(1,1,0,0,1),(0,1,1,0,0),(0,0,0,1,0),(0,1,0,0,1));
  name:array[five] of
string[5]=(‘zhang’,’wang’,’liu’,’zhao’,’qian’);
  var book:array[five] of five;
  flag:set of five;
  c:integer;
 procedure print;
 var i:integer;
 begin
  inc(c);
  writeln(‘answer’,c,’:’);
  for i:=1 to 5 do
   writeln(name[i]:10,’:’,chr(64+book[i]));
 end;
 procedure try(i:integer);
 var j:integer;
 begin
  for j:=1 to 5 do
   if not(j in flag) and (like[i,j]>0) then
    begin flag:=flag+[j];
          book[i]:=j;
          if i=5 then print else try(i+1);
          flag:=flag-[j];
   end
end;
begin
 flag:=[];
 c:=0;
 try(1);
 readln;
end.

因此非递归方法编程如下:

program allotbook;
 type five=1..5;
 const like:array[five,five] of 0..1=
  ((0,0,1,1,0),(1,1,0,0,1),(0,1,1,0,0),(0,0,0,1,0),(0,1,0,0,1));
  name:array[five] of
string[5]=(‘zhang’,’wang’,’liu’,’zhao’,’qian’);
  var book:array[five] of five;
  flag:set of five;
  c,dep,r:integer;
  p:boolean;
 procedure print;
 var i:integer;
 begin
  inc(c);
  writeln(‘answer’,c,’:’);
  for i:=1 to 5 do
   writeln(name[i]:10,’:’,chr(64+book[i]));
 end;
begin
 flag:=[];
 c:=0;dep:=0;
 repeat
  dep:=dep+1;
  r:=0;
  p:=false;
  repeat
  r:=r+1;
  if not(r in flag) and (like[dep,r]>0) then
   begin
    flag:=flag+[r];
    book[dep]:=r;
    if dep=5 then print else p:=true
   end
   else if r>=5 then
    begin
     dep:=dep-1;
     if dep=0 then p:=true else begin r:=book[dep];flag:=flag-[r]
end;
    end else p:=false;
  until p=true;
until dep=0;
 readln;

 

在运用树结构解决问题经常,往往要求本某种次序获得树中全部结点的信息,这种操作

受作树的遍历。遍历的方式来多,常用的发生:

A、先序(根)遍历:先拜访根结点,再从左到右按照前先后思想遍历各棵子树。

如果达到图前先后遍历的结果吧:ABEKLFCGDHMIJ;

B、后序(根)遍历:先从左到右遍历各棵子树,再看根结点。如达到图后先后

遍历的结果为:KLEFBGCMHIJDA;

C、层次遍历:据层次从小到充分逐个看,同一层次按照从左到右的主次。

若是齐图层次遍历的结果也:ABCDEFGHIJKLM;

大家可看来,AB
两种植艺术的定义是递归的,所以于程序实现时反复也是采用递归的

想想。既通常所说的“深度优先找”。如用前序遍历编写的历程如下:

procedure tra1(t,m)   {递归}

begin

if t <>nil then begin

               write(t^.data,’  ’);      {访问根结点}

               for I:=1to m do             {前序遍历各子树}

tra1(t^.child[I],m);

end;

end;

C
这种方法运用也比较多,实际上是咱以的“广度优先找”。思想如下:若有结点

深受访问,则该结点的子结点应登录,等待被访。顺序访问各国层次上结点,直至不再有未访

问过的结点。为者,引入一个班来储存等看的子结点,设一个队首和队尾指针分别表

示出队、进队之下标。程序框架如下:

Const n=100;

Var hend,tail,I:integer;

    Q:array[1..n] of tree;

    P:tree;

Begin

  Tail:=1;head:=1;

  Q[tail]:=t;                       {t进队}

  Tail:=tail+1;

  While ( head<tail) do             {队列非空}

    Begin

      P:=q[head];                   {取出队首结点}

      Head:=head+1;

      Write(p^.data,‘   ‘);       {访问有结点}

      For I:=1 to m do              {该结点的所有子结点按顺序进队}

         If p^.child[I]<>nil   then  begin 

q[tail]:=p^.child[I];

tail:=tail+1;

                                      end;

    End;

End;

 Chaobs编辑,转载请注明出处

相关文章