2.5删除有序表中所有值大于且小于的数据元素。
分析:删除的结点的特点
while(p && p->data <= mink)
{
pre=p;
p=p->next;
if(p)
{
while(p&& p->data < maxk)
p= p->next;
q= pre->next;
pre->next= p;
while(q!= p)
{
s= q;
q= q->next;
free(s);
}
}
}
2.8已知A,B和C为三个有序链表,编写算法从A表中删除B表和C表中共有的数据元素。
分析:被删元素的特点为:ai=bj=ck
其它元素则为:ai<bj 或bj<ck 或ck<ai
设三个指针pa,pb和pc分别指向这三个链表中的相应结点,则算法中的主要操作:
if(pa->data < pb->data)
{
pre= pa;
pa= pa->next;
}
else if(pb->data < pc->data)
pb= pb->next;
else if(pc->data < pa->data)
pc= pc->next;
else
{
//删除
pre-next= pa->next;
free(pa);
pa= pre->next;
}
1.9 双向循环链表的结点中,增加一个访问频度的数据域freq,编写算法实现LOCATE(L,x).
分析:
1)算法的基本操作应该是在链表中进行行搜索,直至p->data = x为止
2)在访问频度freq增1之后,需将该节点调整到适当位置。向前搜索直至找到一个访问频度大于它的结点为止。
p=L->next; //L为双向链表的头指针
while(p != L && p->data != x)
{
p=p->next;//搜索元素值为x的结点
}
if(p == L)
{
returnNULL;
}
q = p->priou;
while(q != L && q->freq <p->freq)
q= q->prion; //搜索访问频度不小于它的结点
//删除结点*p
//将结点*p插入在结点*q之后;
3.2给出区分给定的“栈操作”序列是否合法的准则,并证明两个不同的合法蓄力不可能得到相同的输出元素序列。空栈到空栈
准则:
1)从操作序列中第一个字符起的任何一个子序列中,‘S’的个数不少与‘X’的个数;
2)整个序列中,‘S’的个数和‘X’的个数相同。
证明:(用反证法)
假设两个不同的合法操作序列:T1=u1,u2,…,un, T2=v1,v2,…,vn ui,vi∈{S,X} i=1,2,..,n 可以得到相同的输出元素序列。
不失一般性,假设第一个不同的操作为:
Uk=’S’ <> vk=’X’ 即:uj=vj,j=1,2,…k-1
则此时,已输出的元素序列相同,栈的状态也相同,且栈中至少存在一个元素。
假设,栈顶元素为b,正待输入的元素a,则根据栈的后进先出的原则,由T1得到的输出序列中,a领先于b。而由T2得到的输出序列中,b领先于a。
由此证得,两个不同的合法操作序列不肯能得到相同的输出元素序列。
3.6
status test(int &sum)
{
intx;
scanf(x);
if(!x)
sum= 0;
else
{
test(sum);
sum+= x;
printf(sum);
}
}
设输入为:5,3,1,0
则输出为:0,1,4,9
从上述运行结果可见,输出顺序和输入顺序恰好相反,则消去递归时必须用栈。
void ditui(int sum)
{
InitStack(S);
scanf(x);
while(x)
{
Push(S,x);
scanf(x);
}
sum= 0;
printf(sum);
while(!StackEmpty(S))
{
sum+= Pop(S);
printf(sum);
}
}
3.8识别读入一个的反对称的字符序列。
例如:abcd&dcba@是反对称字符序列;abc&@或abc&abc@ 或 ab&bac@ 都不是反对称字符序列。
这个算法和“判别括弧是否正确匹配的算法极其相似,算法过程中需要用到一个栈,由于序列中必定出现字符‘&’,则可以将在字符‘&’出现之前的所有字符均入栈,虑去字符‘&’之后再读入字符则应和栈顶的字符相等。
1.15 判别读入的字符序列是否为“回文”。
例如:abcdecdba 或 abccba 是回文。
由于回文的字符序列中的分界线不明确,因此算法中,除了需要一个栈之外,还需要一个队列,否则无法判别。
算法的基本思想是:
将依次读入的字符分别插入栈和队列,然后依次比较“栈顶”和“队头”的字符。
Status ex315()
{
InitStack(S);
InitQueue(Q);
scanf(ch);
while(ch!='@')
{
Push(S,ch);
EnQueue(Q,ch);
scanf(ch);
}
state= TRUE;
while(!StackEmpty && state)
{
if(GetTop(S)== GetHead(Q))
{
Pop(S);
DeQueue(Q);
}
else
{
state= False;
}
}
returnstate;
}
1.7 从串S中删除所有和串T相同的子串。
此题的操作等同于“以空串置换串S中所有和T串相同的子串。”
显然,算法的目标是构造如上所画的一个新串。
下一次搜索串的起始位置为:
pos=k+StrLength(T)
n = StrLength(S);
m = StrLength(T);
k = pos = 1;
StrAssign(news,'');
while(k <= n-m+1)
{
sub= SubString(S, k, m);
if(StrCompare(sub,T) != 0)
k++;
else
{
news= Concat(new, SubString(S, pos, k-pos));
pos= k + n;
k= pos;
}
}
news = Concat(news SubString(S, pos,n-pos+1));
4.11 求串S中出现的第一个最长重复子串及其位置。所谓“重复子串”指的是,
SubString(S,i,len) == SubString(S,j,len)
1<=i<j<=StrLength(S)
1<=len<=StrLength(S)-j+1
例如:S=’aaaaaaa’的最长重复子串为T=’aaaaaa’
分析:
此题可以有多种解法,在此只介绍一种利用求next函数的算法
next[j]<>0 表明:在第j个字符之前存在一个长度为next[j]-1的重复子串。
由此,算法的基本思想为:求串 pat=SubString(S,i,StrLength(S)-i+1)的next函数值,i=1,2,…,StrLength(S)-1并从中求最大值。
例如:S=’abaabaaabaaaab’
Pat1 = ‘abaabaaabaaaab’
Next值01122345234522
Pat2 = ’ baabaaabaaaab’
Next值0111234123411
Pat3= ‘aabaaabaaaab’
Next值 012123345673
Pat4 = ’abaaabaaaab’
Next值 01122234562
特殊情况:注意最后一个字符!
如果:字符串aabaaabaaaba
Next 值为 012121345678
i = 1;
maxl = 0; //当前重复子串的长度
n = S[0];
while(n-i+1 > maxl)
{
maxk= Max
{
Next(SubString(S,i, n-1+1))
}
if(maxk!= next[n] || S[n] != S[i+maxk-1])
maxk--;
if(maxk> maxl)
{
maxl= maxk;
pos= i;
}
i++;
}
6.2二叉树
基本操作:
查找插入删除
查找:
Root(T);
Parent(T,cur_e)
LeftChild(T,cur_e)
RightChild(T,e)
LeftSibling(T,cur_e)
RightSibling(T,cur_e)
BiTreeEmpty(T);
BitTreeDepth(T);
PreOrderTraverse(T,Visit());
InOrderTraverse(T,Visit());
PostOrderTraverse(T,Visit());
LevelOrderTraverse(T,Visit());
插入:
InitBiTree(&T);
CreateBiTree(&T,definition);
Assign(T,&e,value);
InsertChild(T,p,LR,c);
删除:
ClearBiTree(&T);
DestoryBiTree(&T);
DeleteChild(&T,p,LR);
二叉树的重要特性
性质1:在二叉树的第i层上至多有2^(i-1)个结点 (i>1)
性质2:深度为k的二叉树上至多含(2^k)-1个结点(k>1)
性质3:对任何一棵二叉树,若他含有n0个叶子结点,n2个度为2的结点,则必存在关系式:n0=n2+1
两类特殊的二叉树
满二叉树:指的是深度为k且含有2^k-1个结点的二叉树。
完全二叉树:树中所含的n个结点和满二叉树中编号为1至n的结点一一对应
性质4:具有n个结点的完全二叉树树的深度为[log2n]+1向下取整在加一
性质5: 若含n个结点的二叉树从上到下且从左到右进行1至n的编号,则对二叉树中任意一个编号为i的结点:
(1) 若i=1,则该结点是二叉树的根,无双亲。否则,编号为[i/2]的结点为其双亲结点。
(2) 若2i>n,则该结点无左孩子结点,否则,编号为2i的结点为其左孩子结点;
(3) 若2i+1>n,则该节点无右孩子结点,否则,编号为2i+1的结点为其右孩子结点。