学习 严蔚敏讲数据结构笔记17
来源:互联网 发布:做淘宝仓库打包员累吗 编辑:程序博客网 时间:2024/05/19 13:14
5.5 广义表的表示方法
头、尾指针的链表结构
表结点:
Tag=1
Hp
Tp
原子结点:
Tag=0
Data
构造存储结构的两种分析方法:
1) 空表 ls=NIL
非空表
若表头为原子,则为
0
Data
否则,依次类推。
2) 空表ls=NIL
非空表LS=(a1,a2,…,an)
若子表为原子,则为
0
Data
否则,依次类推
5.6 广义表操作的递归函数
递归函数:一个含直接或间接调用本函数语句的函数被称之为递归函数,它必须满足以下两个条件:
1)在每一次调用自己时,必须是(在某种意义上)更接近于解;
2)必须有一个终止处理或计算的准则。
例如:梵塔的递归函数
30_001
void hanoi(int n, char x, char y, char z)
{
if(n == 1)
move(x, 1, z);
else
{
hanoi(n-1, x, z, y);
move(x, n, z);
hanoi(n-1, y, x, z);
}
}
例如:二叉树的遍历
30_002
void PreOrderTraverse(BiTree T, void(Visit)(BiTree P))
{
if(T)
{
Visit(T->data);
PreOrderTraverse(T->lchild, Visit);
PreOrderTraverse(T->rchild, Visit);
}
}//PreOrderTraverse
这一类问题可以借助算法设计的一种方法—分治法(分割求解)(Divide and Conquer)来求解。
分治法的设计思想为:
对于一个输入规模为n的函数或问题,用某种方法把输入分割成k(1<k<=n)个子集,从而产生l个子问题,分别求解这l个问题,得出l个问题的子解,在用某种方法把它们组合成原来的问题的解,若子问题还相当大,则可以反复使用分治法,直至最后所分得的子问题足够小,以至可以直接求解为止。
在利用分治法求解时,所得子问题的类型常常和原问题相同,因而很自然地导致递归求解。
例如:梵塔问题:Hanoi(n,x,y,z)可以分解成三个子问题
1) Hanoi(n-1, x, y, z) –递归
2) Move(n, ‘X’->’Z’)
3) Hanoi(n-1,y,x,z) –递归
n=1时可以直接求解
二叉树的遍历Traverse(BT)分成三个子问题
1) Visite(RootNod)
2) Traverse(LBT) –递归
3) Traverse(RBT)—递归
对空树不需要遍历
广义表从结构上可以分解成广义表=表头+表尾或者广义表=子表1+子表2+……+子表n
依次常用分治法求解。
广义表的头尾链表存储表示:
30_003
typedef enum{ATOM, LIST} ElemTag; //ATOM==0:原子,LIST==1:子表
typedef struct GLNode
{
ElemTag tag;
union
{
AtomType atom;
struct{struct GLNode *hp, *tp}ptr;
};
} *Glist;
例一求广义表的深度
广义表的深度=Max{z子表的深度}+1
空表的深度= 1 原子的深度=0
30_004
int GlistDepth(Glist L)
{
if(! L)
{
return 1;
}
if(L->tag == ATOM)
{
return 0;
}
for(max = 0, pp = L; pp; pp = pp->ptr.tp)
{
dep = GlistDepth(pp->ptr.hp);
if(dep > max)
{
max = dep;
}
}
return max + 1;
}//GlistDepth
例二复制广义表
若ls=NIL则newls=NIL
否则由表头ls^.hp复制得newhp由表尾ls^.tp复制得newtp构造结点newls,并使newls^.hp=newhp,newls^.tp=newtp
31_001
Status CopyGList(Glist &T, Glist L)
{
if(! L)
{
T = NULL; //复制空表
}
else
{
if(! (T = (Glist) malloc(sizeof(GLNode))))
{
exit(OVERFLOW); //建表结点
}
T->tag = L->tag;
if(L->tag == ATOM)
{
T->atom = L->atom;
}
else
{
CopyGlist(T->ptr.hp, L->ptr.hp);
CopyGlist(T->ptr.tp, L->ptr.tp);
}//else
}//else
return OK;
}
例三创建广义表的存储结构
根据LS=’(a1,a2,…,an)’建广义表ls
若LS=’()’则ls=NIL
否则构造表结点ls^
分解出第一个子串a1,对应建广义表的表头ls^.hp
若剩余串非空,则构造表尾结点ls^.tp分解出第二个子串a2,对应广义表,依次类推,直至剩余串为空串为止。
31_002
void CreateGList(Glist &L, String S)
{
if(空串) L = NULL; //创建空表
else
{
L = (Glist) malloc(sizeof(GLNode));
L->tag = List;
p = L;
sub = SubString(S, 2, StrLength(S) - 1); //脱外层括弧
do
{
//重复建n个子表
sever(sub, hsub); //分离出子表hsub = a1
if(StrLength(hsub) == 1)
{
p->ptr.hp = (GList) malloc(sizeof(GNolde));
p->ptr.hp->tag = ATOM;
p->ptr.hp->atom = hsub; //创建单原子
}
else
{
CreateGList(p->ptr.hp, hsub); //递归建子表
}
if(! StrEmpty(sub)
{
p->ptr.tp = (Glist) malloc(sizeof(GLNode));
p = p->ptr.tp; //建表尾结点*p
}
}while(! StrEmpty(sub));
p->ptr.tp = NULL;
}//else
}
删除单链表中所有值为x的数据元素
分析:
1) 单链表是一种顺序结构,必须从第一个结点起,逐个检查每个结点的数据元素;
2) 从另一角度看,链表又是一个递归结构,若L是线性表(a1,a2,…,an)的头指针,则L->next是线性链表(a2,…,an)的头指针。
31_003
void delete(LinkList &L, ElemType x)
{
//L为无头结点的单链表的头指针
if(L)
{
if(L->data = x)
{
p = L;
L = L->next;
free(p);
delete(L, x);
}
else
{
delete(L->next, x);
}
}
}
删除广义表中所有元素为x的原子结点
分析:广义表和线性表比较:
相似处:都是顺序结构
不同处:广义表的数据元素可能还是广义表;删除时,不仅要删除原子结点,还需要删除相应的表结点
综合几点:
1. 对于含有递归特性的问题,最好设计递归形式的算法。但也不要单纯追求形式,应在算法设计的分析过程中“就事论事”。例如,在利用分割求解设计算法时,子问题和原问题的性质相同;或者,问题的当前一步解决之后,余下的问题性质相同,则自然导致递归求解。
2. 实现递归函数,目前必须利用“栈”。一个递归函数必定能改写为利用栈实现的非递归函数函数;反之,一个用栈实现的非递归函数可以改写为递归函数。需要注意的是递归层次的深度决定所需存储量的大小。
3. 分析递归算法的工具是递归树,从递归树上可以得到递归函数的各种相关信息。例如:递归树的深度即为递归函数的递归深度;递归树上的结点数目恰为函数中的主要操作重复进行的次数;若递归树蜕化为单枝树或者递归树中含有很多相同的结点,则表明该递归函数不适用。
4. 递归函数中的尾递归容易消除。
32_001
void PreOrderTraverse(BiTree T)
{
While(T)
{
Visit(T->data);
PreOrderTraverse(T->lchild);
T = T->rchild;
}
}//PreOrder
5. 可以用递归方程来表述递归函数的时间性能。
例如:假设解n个圆盘的梵塔的执行时间为T(n),则递归方程为:T(n)=2T(n-1)+C,初始条件为:T(0)=0
第5章广义表
补:
4.掌握广义表的结构特点及其存储表示方法,读者可以根据自己的学习习惯熟练掌握任意一种结构的链表,学会对非空广义表进行分解的两种分析方法:即可将一个非空广义表分解为表头和表尾两部分或者分解为n个子表。
5.学习利用分治法的算法设计思想编制递归算法的方法。
- 学习 严蔚敏讲数据结构笔记17
- 学习 严蔚敏讲数据结构笔记01
- 学习 严蔚敏讲数据结构笔记02
- 学习 严蔚敏讲数据结构笔记03
- 学习 严蔚敏讲数据结构笔记04
- 学习 严蔚敏讲数据结构笔记05
- 学习 严蔚敏讲数据结构笔记06
- 学习 严蔚敏讲数据结构笔记07
- 学习 严蔚敏讲数据结构笔记08
- 学习 严蔚敏讲数据结构笔记09
- 学习 严蔚敏讲数据结构笔记10
- 学习 严蔚敏讲数据结构笔记11
- 学习 严蔚敏讲数据结构笔记12
- 学习 严蔚敏讲数据结构笔记13
- 学习 严蔚敏讲数据结构笔记14
- 学习 严蔚敏讲数据结构笔记15
- 学习 严蔚敏讲数据结构笔记16
- 学习 严蔚敏讲数据结构笔记18
- 学习 严蔚敏讲数据结构笔记12
- 学习 严蔚敏讲数据结构笔记13
- 学习 严蔚敏讲数据结构笔记14
- 学习 严蔚敏讲数据结构笔记15
- 学习 严蔚敏讲数据结构笔记16
- 学习 严蔚敏讲数据结构笔记17
- 学习 严蔚敏讲数据结构笔记18
- 学习 严蔚敏讲数据结构笔记19
- 学习 严蔚敏讲数据结构笔记20
- 黑马训练营——java内存分配
- loadrunner常见问题汇总
- .net中获取周一、月初、月末、年初、年末
- C#索引器
- 串口通信