学习 严蔚敏讲数据结构笔记11

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,BC为三个有序链表,编写算法从A表中删除B表和C表中共有的数据元素。

分析:被删元素的特点为:ai=bj=ck

其它元素则为:ai<bj bj<ck ck<ai

设三个指针pa,pbpc分别指向这三个链表中的相应结点,则算法中的主要操作:

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)在访问频度freq1之后,需将该节点调整到适当位置。向前搜索直至找到一个访问频度大于它的结点为止。

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);

         }

}

设输入为:5310

则输出为:0149

从上述运行结果可见,输出顺序和输入顺序恰好相反,则消去递归时必须用栈。

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’

Next01122345234522

Pat2 = ’ baabaaabaaaab’

Next0111234123411

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个结点和满二叉树中编号为1n的结点一一对应

性质4:具有n个结点的完全二叉树树的深度为[log2n]+1向下取整在加一

性质5: 若含n个结点的二叉树从上到下且从左到右进行1n的编号,则对二叉树中任意一个编号为i的结点:

(1)      i=1,则该结点是二叉树的根,无双亲。否则,编号为[i/2]的结点为其双亲结点。

(2)      2i>n,则该结点无左孩子结点,否则,编号为2i的结点为其左孩子结点;

(3)      2i+1>n,则该节点无右孩子结点,否则,编号为2i+1的结点为其右孩子结点。

 

你可能感兴趣的:(学习 严蔚敏讲数据结构笔记11)