chap 1 引论
算法基本法则
- 基准情形
- 不断递进(向基准情形)
- 设计法则 假设所有递归调用都能运行
- 合成效益法则 求解一个问题同一实例避免重复性工作
chap3 表 栈 队列
3.1 抽象数据类型(ADT)
3.2表ADT
- 后继 前驱
- 可能的几个运算
printList MakeEmpty Find Insert Delete
表——数组实现
运算 | 是否容易实现 | 具体实现方法 |
---|---|---|
PrintList | Yes | for遍历 |
MakeEmpty | Yes | for遍历 or strcpy |
Find | – | 查找算法 |
Next/previous | – | 查找算法 |
Insert | no | 后移其后所有元素 |
Delete | no | 前移其后所有元素 |
链表
-
不连续储存
-
Insert Delete实现
-
细节
- 在表头增删有问题
- 考虑添加一个虚拟的,而不属于待处理数组的表头
- 编写function:FindPrevious以判断前驱节点,当检测为
A
1
A_1
A1时返回表头header地址
- 在表头增删有问题
-
表ADT代码实现
- ADT的声明
/*头文件.h中*/ //作为类型的List(表)和Postion(位置)、各函数名写在其中
#ifndef _List_H
struct Node; //声明结点结构体类型
typedef struct Node *PtrToNode;//声明节点指针类型
typedef PtrToNode List;//声明指针表(以表头地址表示)的类型
typedef PtrTonode position;//声明 节点地址的类型
List MakeEmpty(List L);
int IsEmpty(List L);
int IsLast(Postion P,List L)
Postion Find(ElementType X,List L);
void Delete(ElementType X,List L);
Position FindPrevious(ElementType X,List L);
void Insert(ElementType X,List L,Position P);
void DeleteList(List L);
position Header(List L); //找到(虚拟)表头A_0
Position First(List L); //找到第一个元素A_1
Position First(List L);
ElementType Retrieve(position P);//检索(给地址找出元素)
#endif /*_List_H*/
/*源文件.c*中*/ //具体的Node声明则在这里
struct Node
{
ElementType Element;
Position Next;
}
这里用不同名字细分PtrToNode非常值得学习
不局限于实质一样就叫一个名字
- 具体函数实现
//判断是否是空表
/* Return true if L is empty*/
int IsEmpty(list L)
{
return L->Next==NULL;//如果判等则为真返回1;
}
//判断是否是表末元素
//Return true if P is the last position in list L
//Parameter L is unused in this implementation
int
Islast(Postion P,List L)
{
return P->Next==NULL;
}
//Find 例程
//Return Postion of X in L;NULL if not found
Positon
Find(ElementType X,List L)
{
Positon P;
P=L->Next;//P初始为A_1的地址
while(P!=NULL && P->Element!=X)
p=p->Next;
return P;
}
//Delete 例程
//看图3-3
//Delete first occurrence of X form a list
void
Delete(ElementType X,List L)
{
Position P,TmpCell;
P=FindPrevious(X,L);
if(!IsLast(X,L))
{
TmpCell=P->Next; //TmpCell此时指向X
p->Next=tmpCell->Next;//TmpCell->指向X后面一个元素
}
}
//其中FindPrevious实现
//遍历直到地址为P->Next的元素P->Next->Element为X,则此时P即为所求
//如果是空表则返回表头A_0;
//如果没有找到X(最后一个元素LastNode->Next=NULL则跳出while,末尾元素地址;
Positon
FindPrevious(ElementType X,List L)
{
Position P;
P=L; //P从表头开始
while(P->Next!=NULL&&P->Next->Element!=X)
P=P->Next;
return P;
}
//Insert 例程
//看图3-4
//将新元素插入到A_p之后
//Parameter L is unused in this implementation
void
Insert(Element X,List L,Position P)
{
Position TmpCell;
TmpCell=malloc(sizeof(struct Node));
if(TmpCell==NULL)
FatalError("Out of space!"); //申请内存,内存不够了报警
TmpCell->Element=x;
TmpCell->Next=P->Next;
P->Next=TmpCell;
}
上述插入Insert亦可以用于实现链表创建。
可以注意到,每次增加一个元素,通过调用malloc向系统申请一个随机位置得到一个节点Node需要的内存,这个malloc申请的内存并不是临时的,而是将来这个链表对应的节点长期使用的。
区分Delete每次调用都应当有一个free内存的过程,否则删除之后永久占用
void
DeleteList(List L)
{
Positon P,Tmp;
P=L->Next;
L->Next=NULL; //让表头直接移开
//但是肯定要把占用内存清理了,目前P指向A_1,我们依次删除
while(P!=NULL)
{
Tmp=P->Next; //删之前记录下下一个结点地址
free(p); //打扫干净这个结点
//对应的malloc是在创建表的时候的每个元素对应的Insert里头的malloc
P=tmp; //接下来打扫下一个结点
}
}
- 双链表 和 循环链表