文章目录

  • 绪论
  • 线性表
  • 栈和队列
  • 串、数组和广义表
  • 树和二叉树
  • 查找
  • 排序
  • 小结

绪论










线性表






1.将两个递增的有序链表合并为一个递增的有序链表。要求结果链表仍使用原两个链表的存储空间, 不另外占用其它的存储空间。表中不允许有重复的数据。

合并后的新表使用头指针 LcL_cLc​ 指向,pap_apa​ 和 pbp_bpb​ 分别是链表 LaL_aLa​ 和 LbL_bLb​ 的工作指针,初始化为相应链表的第一个结点,从第一个结点开始进行比较,当两个链表 LaL_aLa​ 和 LbL_bLb​ 均为到达表尾结点时,依次摘取其中较小者重新链接在Lc表的最后。如果两个表中的元素相等,只摘取 LaL_aLa​ 表中的元素,删除 LbL_bLb​ 表中的元素,这样确保合并后表中无重复的元素。当一个表到达表尾结点,为空时,将非空表的剩余元素直接链接在 LcL_cLc​ 表的最后

void MergeList(LinkList &La,LinkList &Lb,LinkList &Lc)
{//合并链表La和Lb,合并后的新表使用头指针Lc指向pa=La->next;  pb=Lb->next;    //pa和pb分别是链表La和Lb的工作指针,初始化为相应链表的第一个结点Lc=pc=La;  //用La的头结点作为Lc的头结点while(pa && pb){if(pa->data<pb->data){pc->next=pa;pc=pa;pa=pa->next;}//取较小者La中的元素,将pa链接在pc的后面,pa指针后移else if(pa->data>pb->data) {pc->next=pb; pc=pb; pb=pb->next;}//取较小者Lb中的元素,将pb链接在pc的后面,pb指针后移else //相等时取La中的元素,删除Lb中的元素{pc->next=pa;pc=pa;pa=pa->next;q=pb->next;delete pb;pb =q;}}pc->next=pa?pa:pb;    //插入剩余段delete Lb;            //释放Lb的头结点
}

2.将两个非递减的有序链表合并为一个非递增的有序链表。要求结果链表仍使用原来两个链表的存储空间, 不另外占用其它的存储空间。表中允许有重复的数据。

合并后的新表使用头指针 LcL_cLc​ 指向,pap_apa​ 和 pbp_bpb​ 分别是链表 LaL_aLa​ 和 LbL_bLb​ 的工作指针,初始化为相应链表的第一个结点,从第一个结点开始进行比较,当两个链表 LaL_aLa​ 和 LbL_bLb​ 均为到达表尾结点时,依次摘取其中较小者重新链接在 LcL_cLc​ 表的表头结点之后,如果两个表中的元素相等,只摘取 LaL_aLa​ 表中的元素,保留 LbL_bLb​ 表中的元素。当一个表到达表尾结点,为空时,将非空表的剩余元素依次摘取,链接在 LcL_cLc​ 表的表头结点之后。

void MergeList(LinkList& La, LinkList& Lb, LinkList& Lc, )
{//合并链表La和Lb,合并后的新表使用头指针Lc指向pa=La->next;  pb=Lb->next; //pa和pb分别是链表La和Lb的工作指针,初始化为相应链表的第一个结点Lc=pc=La; //用La的头结点作为Lc的头结点 Lc->next=NULL;while(pa||pb ){//只要存在一个非空表,用q指向待摘取的元素if(!pa)  {q=pb;  pb=pb->next;}//La表为空,用q指向pb,pb指针后移else if(!pb)  {q=pa;  pa=pa->next;} //Lb表为空,用q指向pa,pa指针后移else if(pa->data<=pb->data)  {q=pa;  pa=pa->next;}//取较小者(包括相等)La中的元素,用q指向pa,pa指针后移else {q=pb;  pb=pb->next;}//取较小者Lb中的元素,用q指向pb,pb指针后移q->next = Lc->next;  Lc->next = q;   //将q指向的结点插在Lc 表的表头结点之后}delete Lb;             //释放Lb的头结点
}

3.已知两个链表 AAA 和 BBB 分别表示两个集合,其元素递增排列。请设计算法求出 AAA 与 BBB 的交集,并存放于AAA 链表中。

只有同时出现在两集合中的元素才出现在结果表中,合并后的新表使用头指针 LcL_cLc​ 指向。pap_apa​ 和 pbp_bpb​ 分别是链表 LaL_aLa​ 和 LbL_bLb​ 的工作指针,初始化为相应链表的第一个结点,从第一个结点开始进行比较,当两个链表 LaL_aLa​ 和 LbL_bLb​ 均为到达表尾结点时,如果两个表中相等的元素时,摘取 LaL_aLa​ 表中的元素,删除 LbL_bLb​ 表中的元素;如果其中一个表中的元素较小时,删除此表中较小的元素,此表的工作指针后移。当链表LaL_aLa​ 和 LbL_bLb​ 有一个到达表尾结点,为空时,依次删除另一个非空表中的所有元素。

void Mix(LinkList& La, LinkList& Lb, LinkList& Lc)
{  pa=La->next;pb=Lb->next; //pa和pb分别是链表La和Lb的工作指针,初始化为相应链表的第一个结点Lc=pc=La; //用La的头结点作为Lc的头结点while(pa&&pb){ if(pa->data==pb->data)∥交集并入结果表中。{ pc->next=pa;pc=pa;pa=pa->next;u=pb;pb=pb->next; delete u;}else if(pa->data<pb->data) {u=pa;pa=pa->next; delete u;}else {u=pb; pb=pb->next; delete u;}}while(pa) {u=pa; pa=pa->next; delete u;} //释放结点空间while(pb){u=pb; pb=pb->next; delete u;} //释放结点空间pc->next=null;//置链表尾标记。delete Lb;  //释放Lb的头结点
}

4.已知两个链表 AAA 和 BBB 分别表示两个集合,其元素递增排列。请设计算法求出两个集合 AAA 和 BBB 的差集(即仅由在 AAA 中出现而不在 BBB 中出现的元素所构成的集合),并以同样的形式存储,同时返回该集合的元素个数。

求两个集合 AAA 和 BBB 的差集是指在 AAA 中删除 AAA 和BBB 中共有的元素,即删除链表中的相应结点,所以要保存待删除结点的前驱,使用指针 preprepre 指向前驱结点。pap_apa​ 和 pbp_bpb​ 分别是链表 LaL_aLa​ 和LbL_bLb​ 的工作指针,初始化为相应链表的第一个结点,从第一个结点开始进行比较,当两个链表 LaL_aLa​ 和 LbL_bLb​ 均为到达表尾结点时,如果 LaL_aLa​ 表中的元素小于 LbL_bLb​ 表中的元素,preprepre 置为 LaL_aLa​ 表的工作指针 pap_apa​ 删除 LbL_bLb​ 表中的元素;如果其中一个表中的元素较小时,删除此表中较小的元素,此表的工作指针后移。当链表 LaL_aLa​ 和 LbL_bLb​ 有一个为空时,依次删除另一个非空表中的所有元素。

void Difference(LinkList& La, LinkList& Lb,int *n)
{ //差集的结果存储于单链表La中,*n是结果集合中元素个数,调用时为0pa=La->next; pb=Lb->next;      //pa和pb分别是链表La和Lb的工作指针,初始化为相应链表的第一个结点pre=La;          ∥pre为La中pa所指结点的前驱结点的指针while(pa&&pb){if(pa->data<q->data){pre=pa;pa=pa->next;*n++;} // A链表中当前结点指针后移else if(pa->data>q->data)q=q->next;    //B链表中当前结点指针后移else {pre->next=pa->next;  //处理A,B中元素值相同的结点,应删除u=pa; pa=pa->next; delete u;}  //删除结点}
}

5.设计算法将一个带头结点的单链表 AAA 分解为两个具有相同结构的链表BBB、CCC,其中 BBB 表的结点为 AAA 表中值小于零的结点,而 CCC 表的结点为 AAA 表中值大于零的结点(链表 AAA 中的元素为非零整数,要求 BBB、CCC 表利用 AAA 表的结点)。

BBB 表的头结点使用原来 AAA 表的头结点,为 CCC 表新申请一个头结点。从 AAA 表的第一个结点开始,依次取其每个结点 ppp,判断结点 ppp 的值是否小于 0,利用前插法,将小于 0 的结点插入 BBB 表,大于等于0的结点插入 CCC 表。

void DisCompose(LinkedList A)
{   B=A;B->next= NULL; //B表初始化C=new LNode; //为C申请结点空间C->next=NULL;   //C初始化为空表p=A->next;      //p为工作指针while(p!= NULL){ r=p->next;     //暂存p的后继if(p->data<0){p->next=B->next; B->next=p; }//将小于0的结点链入B表,前插法else {p->next=C->next; C->next=p; } //将大于等于0的结点链入C表,前插法p=r; //p指向新的待处理结点。}
}

6.设计一个算法,通过一趟遍历在单链表中确定值最大的结点。

假定第一个结点中数据具有最大值,依次与下一个元素比较,若其小于下一个元素,则设其下一个元素为最大值,反复进行比较,直到遍历完该链表。

ElemType Max (LinkList L )
{if(L->next==NULL) return NULL;pmax=L->next; //假定第一个结点中数据具有最大值p=L->next->next;while(p != NULL ){//如果下一个结点存在if(p->data > pmax->data) pmax=p;//如果p的值大于pmax的值,则重新赋值p=p->next;//遍历链表}return pmax->data;
}

7.设计一个算法,通过遍历一趟,将链表中所有结点的链接方向逆转,仍利用原表的存储空间。

从首元结点开始,逐个地把链表 LLL 的当前结点 ppp 插入新的链表头部。

void  inverse(LinkList &L)
{// 逆置带头结点的单链表 Lp=L->next;  L->next=NULL;while(p){q=p->next;    // q指向*p的后继p->next=L->next;L->next=p;       // *p插入在头结点之后p = q;}
}

8.设计一个算法,删除递增有序链表中值大于mink且小于 maxkmax_kmaxk​ 的所有元素(minkmin_kmink​ 和 maxkmax_kmaxk​ 是给定的两个参数,其值可以和表中的元素相同,也可以不同 )。

分别查找第一个值 > minkmin_kmink​ 的结点和第一个值 ≥ maxkmax_kmaxk​ 的结点,再修改指针,删除值大于 minkmin_kmink​ 且小于 maxkmax_kmaxk​ 的所有元素。

void delete(LinkList &L, int mink, int maxk)
{p=L->next; //首元结点while(p && p->data<=mink){ pre=p;  p=p->next; } //查找第一个值>mink的结点if(p) {while (p && p->data<maxk)  p=p->next;// 查找第一个值 ≥maxk的结点q=pre->next;   pre->next=p;  // 修改指针while(q!=p) {s=q->next;  delete q;  q=s; } // 释放结点空间}
}

9.已知 ppp 指向双向循环链表中的一个结点,其结点结构为 datadatadata、priorpriorprior、nextnextnext 三个域,写出算法 change(p)change(p)change(p), 交换 ppp 所指向的结点和它的前缀结点的顺序。

知道双向循环链表中的一个结点,与前驱交换涉及到四个结点( ppp 结点,前驱结点,前驱的前驱结点,后继结点)六条链。

void  Exchange(LinkedList p)
∥p是双向循环链表中的一个结点,本算法将p所指结点与其前驱结点交换。
{q=p->llink;q->llink->rlink=p;  //p的前驱的前驱之后继为pp->llink=q->llink;  //p的前驱指向其前驱的前驱。q->rlink=p->rlink;  //p的前驱的后继为p的后继。q->llink=p;         //p与其前驱交换p->rlink->llink=q;  //p的后继的前驱指向原p的前驱p->rlink=q;         //p的后继指向其原来的前驱
}  //算法exchange结束。

10.已知长度为 nnn 的线性表 AAA 采用顺序存储结构,请写一时间复杂度为 O(n)O(n)O(n) 、空间复杂度为 O(1)的算法,该算法删除线性表中所有值为 itemitemitem 的数据元素。

在顺序存储的线性表上删除元素,通常要涉及到一系列元素的移动(删第 iii 个元素,第 i+1i+1i+1 至第 nnn 个元素要依次前移)。本题要求删除线性表中所有值为 itemitemitem 的数据元素,并未要求元素间的相对位置不变。因此可以考虑设头尾两个指针(i=1,j=ni=1,j=ni=1,j=n),从两端向中间移动,凡遇到值 itemitemitem 的数据元素时,直接将右端元素左移至值为 itemitemitem 的数据元素位置。

void  Delete(ElemType A[ ],int  n)
//A是有n个元素的一维数组,本算法删除A中所有值为item的元素。
{i=1;j=n;∥设置数组低、高端指针(下标)。while(i<j){while(i<j && A[i]!=item) i++;    //若值不为item,左移指针。if(i<j) while(i<j && A[j]==item)j--; //若右端元素为item,指针左移if(i<j) A[i++]=A[j--];}
}

栈和队列






1.将编号为 0 和 1 的两个栈存放于一个数组空间 V[m]V[m]V[m] 中,栈底分别处于数组的两端。当第 0 号栈的栈顶指针 top[0]top[0]top[0] 等于 -1 时该栈为空,当第 1 号栈的栈顶指针 top[1]top[1]top[1] 等于 mmm 时该栈为空。两个栈均从两端向中间增长。试编写双栈初始化,判断栈空、栈满、进栈和出栈等算法的函数。双栈数据结构的定义如下:

Typedef struct
{int top[2],bot[2]; //栈顶和栈底指针SElemType *V;  //栈数组int m;     //栈最大可容纳元素个数
}DblStack

两栈共享向量空间,将两栈栈底设在向量两端,初始时,左栈顶指针为 -1,右栈顶为 mmm。两栈顶指针相邻时为栈满。两栈顶相向、迎面增长,栈顶指针指向栈顶元素。

int Init()  //栈初始化
{S.top[0]=-1;S.top[1]=m;return 1; //初始化成功
}int push(stk S ,int i,int x)  // 入栈操作
//i为栈号,i=0表示左栈,i=1为右栈,x是入栈元素。入栈成功返回1,失败返回0
{if(i<0||i>1){ cout<<“栈号输入不对”<<endl;exit(0);}if(S.top[1]-S.top[0]==1) {cout<<“栈已满”<<endl;return(0);}switch(i){case 0: S.V[++S.top[0]]=x; return(1); break;case 1: S.V[--S.top[1]]=x; return(1);}
} ElemType pop(stk S,int i)  //退栈操作
//退栈。i代表栈号,i=0时为左栈,i=1时为右栈。退栈成功时返回退栈元素
//否则返回-1
{if(i<0 || i>1){cout<<“栈号输入错误”<<endl;exit(0);}switch(i){case 0: if(S.top[0]==-1) {cout<<“栈空”<<endl;return (-1);}else return(S.V[S.top[0]--]);case 1: if(S.top[1]==m){ cout<<“栈空”<<endl;return (-1);}else return(S.V[S.top[1]++]);}
}  //算法结束int Empty()  //判断栈空
{return (S.top[0]==-1 && S.top[1]==m);
}

2.回文是指正读反读均相同的字符序列,如 “abba”“abba”“abba” 和 “abdba”“abdba”“abdba” 均是回文,但 “good”“good”“good” 不是回文。试写一个算法判定给定的字符向量是否为回文。(提示:将一半字符入栈)

将字符串前一半入栈,然后,栈中元素和字符串后一半进行比较。即将第一个出栈元素和后一半串中第一个字符比较,若相等,则再出栈一个元素与后一个字符比较,……,直至栈空,结论为字符序列是回文。在出栈元素与串中字符比较不等时,结论字符序列不是回文。

#define StackSize 100 //假定预分配的栈空间最多为100个元素
typedef char DataType;//假定栈元素的数据类型为字符
typedef struct
{DataType data[StackSize];int top;
}SeqStack;int IsHuiwen( char *t)
{//判断t字符向量是否为回文,若是,返回1,否则返回0SeqStack s;int i,len;char temp;InitStack( &s);len=strlen(t); //求向量长度for(i = 0; i < len/2; i++)//将一半字符入栈Push(&s,t[i]);while(!EmptyStack(&s)){// 每弹出一个字符与相应字符比较temp=Pop(&s);if(temp != S[i])  return 0 ;// 不等则返回0else i++;} return 1 ; // 比较完毕均相等则返回 1
}
  1. 设从键盘输入一整数的序列:a1,a2,a3,…,ana_1, a_2, a_3,…,a_na1​,a2​,a3​,…,an​,试编写算法实现:用栈结构存储输入的整数,当 ai≠−1a_i≠-1ai​​=−1 时,将 aia_iai​ 进栈;当 ai=−1a_i=-1ai​=−1 时,输出栈顶整数并出栈。算法应对异常情况(入栈满等)给出相应的信息。
#define MAXSIZE 100
typedef int SElemType;
typedef struct{SElemType *base;        //栈底指针SElemType *top;        //栈顶指针int stacksize;
}SqStack;
void InOutS(SqStack &S)
//S是元素为整数的栈,本算法进行入栈和退栈操作。
{InitStack(S);             //初始化栈S。for(i=1; i<=n; i++)    //n个整数序列作处理。{cin>>x;    //从键盘读入整数序列。if(x!=-1)    // 读入的整数不等于-1时入栈。{if(S.top-S.base==S.stacksize){cout<<“栈满,无法入栈!”<<endl; exit(0);}else *S.top++=x; //x入栈。}else   //读入的整数等于-1时退栈。{if(S.top==S.base){cout<<“栈空,无法出栈!”<<endl; exit(0);} else cout<<“出栈元素是”<< *--S.top<<endl;} }
}//算法结束。

4.从键盘上输入一个后缀表达式,试编写算法计算表达式的值。规定:逆波兰表达式的长度不超过一行,以 $ 符作为输入结束,操作数之间用空格分隔,操作符只可能有 +++、−-−、∗*∗、/// 四种运算。例如:234 34+2*$。

逆波兰表达式(即后缀表达式)求值规则如下:设立运算数栈OPNDOPNDOPND,对表达式从左到右扫描(读入),当表达式中扫描到数时,压入OPNDOPNDOPND 栈。当扫描到运算符时,从 OPNDOPNDOPND 退出两个数,进行相应运算,结果再压入 OPNDOPNDOPND 栈。这个过程一直进行到读出表达式结束符 $ ,这时 OPNDOPNDOPND 栈中只有一个数,就是结果。

float expr( )
//从键盘输入逆波兰表达式,以‘$’表示输入结束,本算法求逆波兰式表达式的值。
{float OPND[30];  // OPND是操作数栈。init(OPND);   //两栈初始化。float num=0.0;  //数字初始化。cin>>x; //x是字符型变量。while(x!=’$’){switch{case‘0’<=x<=’9’:while((x>=’0’&&x<=’9’)||x==’.’)  //拼数if(x!=’.’)   //处理整数{num=num*10+(ord(x)-ord(‘0’));cin>>x;}else  //处理小数部分。{scale=10.0; cin>>x;while(x>=’0’&&x<=’9’){num=num+(ord(x)-ord(‘0’)/scale;scale=scale*10;  cin>>x; }}//elsepush(OPND,num); num=0.0;//数压入栈,下个数初始化case x=‘ ’:break;  //遇空格,继续读下一个字符。case x=‘+’:push(OPND,pop(OPND)+pop(OPND));break;case x=‘-’:x1=pop(OPND);x2=pop(OPND);push(OPND,x2-x1);break;case x=‘*’:push(OPND,pop(OPND)*pop(OPND));break;case x=‘/’:x1=pop(OPND);x2=pop(OPND);push(OPND,x2/x1);break;default:       //其它符号不作处理。}//结束switchcin>>x;//读入表达式中下一个字符。}//结束while(x!=‘$’)cout<<“后缀表达式的值为”<<pop(OPND);
}//算法结束。

[算法讨论]假设输入的后缀表达式是正确的,未作错误检查。算法中拼数部分是核心。若遇到大于等于‘0’且小于等于‘9’的字符,认为是数。这种字符的序号减去字符‘0’的序号得出数。对于整数,每读入一个数字字符,前面得到的部分数要乘上10再加新读入的数得到新的部分数。当读到小数点,认为数的整数部分已完,要接着处理小数部分。小数部分的数要除以10(或10的幂数)变成十分位,百分位,千分位数等等,与前面部分数相加。在拼数过程中,若遇非数字字符,表示数已拼完,将数压入栈中,并且将变量num恢复为0,准备下一个数。这时对新读入的字符进入‘+’、‘-’、‘*’、‘/’及空格的判断,因此在结束处理数字字符的case后,不能加入break语句。~

5.假设以I和 OOO 分别表示入栈和出栈操作。栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由 III 和 OOO 组成的序列,称可以操作的序列为合法序列,否则称为非法序列。
①下面所示的序列中哪些是合法的?
A.IOIIOIOOA. IOIIOIOOA.IOIIOIOO
B.IOOIOIIOB. IOOIOIIOB.IOOIOIIO
C.IIIOIOIOC. IIIOIOIOC.IIIOIOIO
D.IIIOOIOOD. IIIOOIOOD.IIIOOIOO
②通过对①的分析,写出一个算法,判定所给的操作序列是否合法。若合法,返回 truetruetrue,否则返回 falsefalsefalse(假定被判定的操作序列已存入一维数组中)。

① AAA 和 DDD 是合法序列,BBB 和 CCC 是非法序列。
②设被判定的操作序列已存入一维数组 AAA 中。

int Judge(char A[])
//判断字符数组A中的输入输出序列是否是合法序列。如是,返回true,否则返回false
{i=0;       //i为下标。j=k=0;     //j和k分别为I和字母O的的个数。while(A[i]!=‘\0’) //当未到字符数组尾就作。{switch(A[i]){case‘I’: j++; break; //入栈次数增1。case‘O’: k++; if(k>j){cout<<“序列非法”<<ednl;exit(0);}}i++; //不论A[i]是‘I’或‘O’,指针i均后移。}if(j!=k) {cout<<“序列非法”<<endl;return(false);}else { cout<<“序列合法”<<endl;return(true);}
}//算法结束。

[算法讨论]在入栈出栈序列(即由 ‘I’‘I’‘I’ 和 ‘O’‘O’‘O’ 组成的字符串)的任一位置,入栈次数( ‘I’‘I’‘I’ 的个数)都必须大于等于出栈次数(即 ‘O’‘O’‘O’ 的个数),否则视作非法序列,立即给出信息,退出算法。整个序列(即读到字符数组中字符串的结束标记 ‘\0’ ),入栈次数必须等于出栈次数(题目中要求栈的初态和终态都为空),否则视为非法序列。

6.假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素站点(注意不设头指针) ,试编写相应的置空队、判队空 、入队和出队等算法。

[题目分析]置空队就是建立一个头节点,并把头尾指针都指向头节点,头节点是不存放数据的;判队空就是当头指针等于尾指针时,队空;入队时,将新的节点插入到链队列的尾部,同时将尾指针指向这个节点;出队时,删除的是队头节点,要注意队列的长度大于1还是等于1的情况,这个时候要注意尾指针的修改,如果等于1,则要删除尾指针指向的节点。

//先定义链队结构:
typedef struct queuenode
{Datatype data;struct queuenode *next;
}QueueNode; //以上是结点类型的定义
typedef struct
{queuenode *rear;
}LinkQueue; //只设一个指向队尾元素的指针void InitQueue( LinkQueue *Q) //置空队
{ //置空队:就是使头结点成为队尾元素QueueNode *s;Q->rear = Q->rear->next;//将队尾指针指向头结点while(Q->rear!=Q->rear->next)//当队列非空,将队中元素逐个出队{s=Q->rear->next;Q->rear->next=s->next;delete s;}//回收结点空间
}int EmptyQueue( LinkQueue *Q) //判队空
{ //判队空。当头结点的next指针指向自己时为空队return Q->rear->next->next==Q->rear->next;
}void EnQueue( LinkQueue *Q, Datatype x) //入队
{ //入队。也就是在尾结点处插入元素QueueNode *p=new QueueNode;//申请新结点p->data=x; p->next=Q->rear->next;//初始化新结点并链入Q-rear->next=p; Q->rear=p;//将尾指针移至新结点
}Datatype DeQueue( LinkQueue *Q) //出队
{//出队,把头结点之后的元素摘下Datatype t;QueueNode *p;if(EmptyQueue(Q))Error("Queue underflow");p=Q->rear->next->next; //p指向将要摘下的结点x=p->data; //保存结点中数据if (p==Q->rear){//当队列中只有一个结点时,p结点出队后,要将队尾指针指向头结点Q->rear = Q->rear->next; Q->rear->next=p->next;}else Q->rear->next->next=p->next;//摘下结点pdelete p;//释放被删结点return x;
}

7.假设以数组 Q[m]Q[m]Q[m] 存放循环队列中的元素, 同时设置一个标志 tagtagtag,以tag==0tag == 0tag==0 和 tag==1tag == 1tag==1 来区别在队头指针 (front)(front)(front) 和队尾指针 (rear)(rear)(rear) 相等时,队列状态为“空”还是“满”。试编写与此结构相应的插入 (enqueue)(enqueue)(enqueue) 和删除 (dlqueue)(dlqueue)(dlqueue) 算法。

SeQueue QueueInit(SeQueue Q) //初始化
{//初始化队列Q.front=Q.rear=0; Q.tag=0;return Q;
}SeQueue QueueIn(SeQueue Q,int e) //入队
{//入队列if((Q.tag==1) && (Q.rear==Q.front)) cout<<"队列已满"<<endl;else {Q.rear=(Q.rear+1) % m;Q.data[Q.rear]=e;if(Q.tag==0) Q.tag=1; //队列已不空}return Q;
}ElemType QueueOut(SeQueue Q) //出队
{//出队列if(Q.tag==0) { cout<<"队列为空"<<endl; exit(0);}else{Q.front=(Q.front+1) % m;e=Q.data[Q.front];if(Q.front==Q.rear) Q.tag=0; //空队列}return(e);
}

8.如果允许在循环队列的两端都可以进行插入和删除操作。要求:
① 写出循环队列的类型定义;
② 写出“从队尾删除”和“从队头插入”的算法。

[题目分析] 用一维数组 v[0..M−1]v[0..M-1]v[0..M−1] 实现循环队列,其中 MMM 是队列长度。设队头指针 frontfrontfront 和队尾指针 rearrearrear,约定 frontfrontfront 指向队头元素的前一位置,rearrearrear 指向队尾元素。定义 front=rearfront=rearfront=rear 时为队空,(rear+1)%m=front(rear+1)\%m=front(rear+1)%m=front 为队满。约定队头端入队向下标小的方向发展,队尾端入队向下标大的方向发展。

#define M  队列可能达到的最大长度
typedef struct
{elemtp data[M];int front,rear;
}cycqueue;elemtp delqueue (cycqueue Q)
//Q是如上定义的循环队列,本算法实现从队尾删除,若删除成功,返回被删除元素,否则给出出错信息。
{if (Q.front==Q.rear)  { cout<<"队列空"<<endl; exit(0);}Q.rear=(Q.rear-1+M)%M;          //修改队尾指针。return(Q.data[(Q.rear+1+M)%M]); //返回出队元素。
}//从队尾删除算法结束void enqueue (cycqueue Q, elemtp x)
// Q是顺序存储的循环队列,本算法实现“从队头插入”元素x。
{if (Q.rear==(Q.front-1+M)%M)  { cout<<"队满"<<endl; exit(0);}Q.data[Q.front]=x;        //x 入队列Q.front=(Q.front-1+M)%M;  //修改队头指针。
}// 结束从队头插入算法。

9.已知 AckermannAckermannAckermann 函数定义如下

① 写出计算 Ack(m,n)Ack(m,n)Ack(m,n) 的递归算法,并根据此算法给出出 Ack(2,1)Ack(2,1)Ack(2,1) 的计算过程。
② 写出计算 Ack(m,n)Ack(m,n)Ack(m,n) 的非递归算法。

//递归算法
int Ack(int m,n)
{if (m==0) return(n+1);else if(m!=0&&n==0) return(Ack(m-1,1));else return(Ack(m-1,Ack(m,m-1));
}//算法结束
 Ack(2,1)的计算过程
Ack(2,1)= Ack(1,Ack(2,0))           = Ack(1,Ack(1,1))            = Ack(1,Ack(0,Ack(1,0)))    = Ack(1,Ack(0,Ack(0,1)))   = Ack(1,Ack(0,2))            = Ack(1,3)                = Ack(0,Ack(1,2))          = Ack(0,Ack(0,Ack(1,1)))    = Ack(0,Ack(0,Ack(0,Ack(1,0)))) = Ack(0,Ack(0,Ack(0,Ack(0,1)))) = Ack(0,Ack(0,Ack(0,2)))   = Ack(0,Ack(0,3))            = Ack(0,4)                   =5
//非递归
int Ackerman(int m, int n)
{int akm[M][N];int i,j;for(j=0;j<N;j++) akm[0][j]=j+1;for(i=1;i<m;i++){akm[i][0]=akm[i-1][1];for(j=1;j<N;j++)akm[i][j]=akm[i-1][akm[i][j-1]];}return(akm[m][n]);
}//算法结束

10.已知f为单链表的表头指针, 链表中存储的都是整型数据,试写出实现下列运算的递归算法:
① 求链表中的最大整数;
② 求链表的结点个数;
③ 求所有整数的平均值。

int GetMax(LinkList p)
{if(!p->next)    return p->data;else{int max=GetMax(p->next);return p->data>=max ? p->data:max;}
}int GetLength(LinkList p)
{if(!p->next)return 1;else{return GetLength(p->next)+1;}
}double GetAverage(LinkList p , int n)
{if(!p->next)return p->data;else{double ave=GetAverage(p->next,n-1);return (ave*(n-1)+p->data)/n;}
}

串、数组和广义表





1.已知模式串 t=‘abcaabbabcab’t=‘abcaabbabcab’t=‘abcaabbabcab’ 写出用 KMPKMPKMP 法求得的每个字符对应的nextnextnext 和 nextvalnextvalnextval 函数值。

模式串 ttt 的 nextnextnext 和 nextvalnextvalnextval 值如下:

2.设目标为 t=“abcaabbabcabaacbacba”t=“abcaabbabcabaacbacba”t=“abcaabbabcabaacbacba”,模式为 p=“abcabaa”p=“abcabaa”p=“abcabaa”
① 计算模式 ppp 的 nextvalnextvalnextval 函数值;
② 不写出算法,只画出利用 KMPKMPKMP 算法进行模式匹配时每一趟的匹配过程。

① p的 nextvalnextvalnextval 函数值为 011013201101320110132。(ppp 的 nextnextnext 函数值 0111232)。
② 利用 KMPKMPKMP (改进的 nextvalnextvalnextval )算法,每趟匹配过程如下:
第一趟匹配: abcaabbabcabaacbacbaabcaabbabcabaacbacbaabcaabbabcabaacbacba
abcab(i=5,j=5)abcab(i=5,j=5)abcab(i=5,j=5)
第二趟匹配: abcaabbabcabaacbacbaabcaabbabcabaacbacbaabcaabbabcabaacbacba
abc(i=7,j=3)abc(i=7,j=3)abc(i=7,j=3)
第三趟匹配: abcaabbabcabaacbacbaabcaabbabcabaacbacbaabcaabbabcabaacbacba
a(i=7,j=1)a(i=7,j=1)a(i=7,j=1)
第四趟匹配: abcaabbabcabaacbacbaabcaabbabcabaac bacbaabcaabbabcabaacbacba
(成功) abcabaa(i=15,j=8)abcabaa(i=15,j=8)abcabaa(i=15,j=8)

3.数组 AAA 中,每个元素 A[i,j]A[i,j]A[i,j] 的长度均为 32 个二进位,行下标从 -1 到 9 ,列下标从 1 到 11,从首地址 SSS 开始连续存放主存储器中,主存储器字长为16 位。求:
① 存放该数组所需多少单元?
② 存放数组第 4 列所有元素至少需多少单元?
③ 数组按行存放时,元素 A[7,4]A[7,4]A[7,4] 的起始地址是多少?
④ 数组按列存放时,元素A[4,7]A[4,7]A[4,7] 的起始地址是多少?

每个元素 32 个二进制位,主存字长 16 位,故每个元素占 2 个字长,行下标可平移至 1 到 11。
(1) 242
(2)22
(3)s+182
(4)s+142

4.请将香蕉 bananabananabanana 用工具 H()—Head()H( )—Head( )H()—Head(),T()—Tail()T( )—Tail( )T()—Tail() 从 LLL 中取出。
LLL=(apple,(orange,(strawberry,(banana)),peach),pear)(apple,(orange,(strawberry,(banana)),peach),pear)(apple,(orange,(strawberry,(banana)),peach),pear)
H(H(T(H(T(H(T(L)))))))

1.写一个算法统计在输入字符串中各个不同字符出现的频度并将结果存入文件(字符串中的合法字符为 A−ZA-ZA−Z 这 26 个字母和 0-9 这 10 个数字)。

由于字母共 26 个,加上数字符号 10 个共 36 个,所以设一长 36 的整型数组,前 10 个分量存放数字字符出现的次数,余下存放字母出现的次数。从字符串中读出数字字符时,字符的 ASCII 代码值减去数字字符 ‘0’ 的 ASCII 代码值,得出其数值 (0…9),字母的 ASCII 代码值减去字符 ‘A’ 的 ASCII 代码值加上10,存入其数组的对应下标分量中。遇其它符号不作处理,直至输入字符串结束。

void Count()
//统计输入字符串中数字字符和字母字符的个数。
{int i,num[36];char ch;for(i=0;i<36;i++) num[i]=0;// 初始化while((ch=getchar())!='#') //‘#’表示输入字符串结束。if(ch>= '0' && ch <= '9'){i=ch-48;num[i]++;}        // 数字字符else if(ch >= 'A' && ch<='Z'){i=ch-65+10;num[i]++;}// 字母字符for(i=0;i<10;i++) // 输出数字字符的个数cout<<"数字 "<<i<<" 的个数 = "<<num[i]<<endl;for(i=10;i<36;i++)// 求出字母字符的个数cout<<"字母字符 "<<i+55<<" 的个数 = "<<num[i]<<endl;
}

2.写一个递归算法来实现字符串逆序存储,要求不另设串存储空间。

[题目分析]实现字符串的逆置并不难,但本题“要求不另设串存储空间”来实现字符串逆序存储,即第一个输入的字符最后存储,最后输入的字符先存储,使用递归可容易做到。

void InvertStore(char A[])
//字符串逆序存储的递归算法。
{char ch;static int i = 0;//需要使用静态变量cin>>ch;if(ch!= '.')    //规定'.'是字符串输入结束标志{InvertStore(A);A[i++] = ch;//字符串逆序存储}A[i] = '\0';  //字符串结尾标记
}

3.编写算法,实现下面函数的功能。函数 voidvoidvoid insert(char∗s,char∗t,intpos)insert(char*s,char*t,int pos)insert(char∗s,char∗t,intpos)将字符串 ttt 插入到字符串 sss 中,插入位置为 pospospos。假设分配给字符串 sss 的空间足够让字符串 ttt 插入。(说明:不得使用任何库函数)

[题目分析]本题是字符串的插入问题,要求在字符串 sss 的pospospos 位置,插入字符串 ttt。首先应查找字符串 sss 的 pospospos 位置,将
第 pospospos 个字符到字符串 sss 尾的子串向后移动字符串 ttt 的长度,然后将字符串 ttt 复制到字符串 sss 的第 pospospos 位置后。
对插入位置 pospospos 要验证其合法性,小于 1 或大于串 sss 的长度均为非法,因题目假设给字符串 sss 的空间足够大,故对插入不必判溢出。

void  insert(char *s,char *t,int pos)
//将字符串t插入字符串s的第pos个位置。
{int i=1,x=0;  char *p=s,*q=t;  //p,q分别为字符串s和t的工作指针if(pos<1) {cout<<"pos参数位置非法"<<endl;exit(0);}while(*p!='\0' && i<pos) {p++;i++;} //查pos位置//若pos小于串s长度,则查到pos位置时,i=pos。if(*p == '/0') { cout<<pos<<"位置大于字符串s的长度";exit(0);}else      //查找字符串的尾while(*p!= '/0') {p++; i++;}  //查到尾时,i为字符‘\0’的下标,p也指向‘\0’。while(*q!= '\0') {q++; x++; }   //查找字符串t的长度x,循环结束时q指向'\0'。for(j=i;j>=pos ;j--){*(p+x)=*p; p--;}//串s的pos后的子串右移,空出串t的位置。q--;  //指针q回退到串t的最后一个字符for(j=1;j<=x;j++) *p--=*q--;  //将t串插入到s的pos位置上
}

[算法讨论] 串s的结束标记(’\0’)也后移了,而串t的结尾标记不应插入到s中。

4.已知字符串 S1S_1S1​ 中存放一段英文,写出算法 format(s1,s2,s3,n)format(s_1,s_2,s_3,n)format(s1​,s2​,s3​,n),将其按给定的长度 nnn 格式化成两端对齐的字符串 S2S_2S2​, 其多余的字符送 S3S_3S3​。

[题目分析]本题要求字符串 s1s_1s1​ 拆分成字符串 s2s_2s2​ 和字符串 s3s_3s3​,要求字符串 s2s_2s2​ “按给定长度 nnn 格式化成两端对齐的字符串”,即长度为 nnn 且首尾字符不得为空格字符。算法从左到右扫描字符串s1s_1s1​,找到第一个非空格字符,计数到 nnn,第 nnn 个拷入字符串 s2s_2s2​ 的字符不得为空格,然后将余下字符复制到字符串 s3s_3s3​ 中。

void format (char *s1,*s2,*s3)
//将字符串s1拆分成字符串s2和字符串s3,要求字符串s2是长n且两端对齐
{char *p=s1, *q=s2;int i=0;while(*p!= '\0' && *p== ' ') p++;//滤掉s1左端空格if(*p== '\0') {cout<<"字符串s1为空串或空格串"<<endl;exit(0);  }while(*p!='\0' && i<n){*q=*p; q++; p++; i++;}//字符串s1向字符串s2中复制if(*p =='\0'){cout<<"字符串s1没有"<<n<<"个有效字符"<<endl; exit(0);}if(*(--q)==' ') //若最后一个字符为空格,则需向后找到第一个非空格字符{p-- ;          //p指针也后退while(*p==' '&&*p!='\0') p++;//往后查找一个非空格字符作串s2的尾字符      if(*p=='\0') {cout<<"s1串没有"<<n<<"个两端对齐的字符串"<<endl; exit(0);}*q=*p;         //字符串s2最后一个非空字符*(++q)='\0';   //置s2字符串结束标记}*q=s3;p++;      //将s1串其余部分送字符串s3。while (*p!= '\0') {*q=*p; q++; p++;}*q='\0';        //置串s3结束标记
}

5.设二维数组 a[1..m,1..n]a[1..m, 1..n]a[1..m,1..n] 含有 m∗nm*nm∗n 个整数。
① 写一个算法判断 aaa 中所有元素是否互不相同?输出相关信息( yes/noyes/noyes/no );
② 试分析算法的时间复杂度。

①[题目分析]判断二维数组中元素是否互不相同,只有逐个比较,找到一对相等的元素,就可结论为不是互不相同。如何达到每个元素同其它元素比较一次且只一次?在当前行,每个元素要同本行后面的元素比较一次(下面第一个循环控制变量 ppp 的 forforfor 循环),然后同第 i+1i+1i+1 行及以后各行元素比较一次,这就是循环控制变量 kkk 和 ppp 的二层 forforfor 循环。

int JudgEqual(ing a[m][n],int m,n)
//判断二维数组中所有元素是否互不相同,如是,返回1;否则,返回0。
{for(i=0;i<m;i++)for(j=0;j<n-1;j++){for(p=j+1;p<n;p++) //和同行其它元素比较if(a[i][j]==a[i][p]) {cout<<"no"; return(0); }//只要有一个相同的,就结论不是互不相同for(k=i+1;k<m;k++)  //和第i+1行及以后元素比较for(p=0;p<n;p++)if(a[i][j]==a[k][p]) { cout<<"no"; return(0); }             }// for(j=0;j<n-1;j++)cout<<"yes"; return(1);  //元素互不相同
}//算法JudgEqual结束

②二维数组中的每一个元素同其它元素都比较一次,数组中共 m∗nm*nm∗n 个元素,第 1 个元素同其它 m∗n−1m*n-1m∗n−1 个元素比较,第 2 个元素同其它 m∗n−2m*n-2m∗n−2 个元素比较,……,第 m∗n−1m*n-1m∗n−1 个元素同最后一个元素 (m∗n)(m*n)(m∗n) 比较一次,所以在元素互不相等时总的比较次数为 (m∗n−1)+(m∗n−2)+…+2+1=(m∗n)(m*n-1)+(m*n-2)+…+2+1=(m*n)(m∗n−1)+(m∗n−2)+…+2+1=(m∗n) (m∗n−1)/2(m*n-1)/2(m∗n−1)/2。在有相同元素时,可能第一次比较就相同,也可能最后一次比较时相同,设在 (m∗n−1)(m*n-1)(m∗n−1) 个位置上均可能相同,这时的平均比较次数约为 (m∗n)(m∗n−1)/4(m*n)(m*n-1)/4(m∗n)(m∗n−1)/4,总的时间复杂度是 O(n4)O(n^4)O(n4)。

6.设任意 nnn 个整数存放于数组 A(1:n)A(1:n)A(1:n) 中,试编写算法,将所有正数排在所有负数前面(要求算法复杂度为 O(n)O(n)O(n))。

[题目分析]本题属于排序问题,只是排出正负,不排出大小。可在数组首尾设两个指针 iii 和 jjj,iii 自小至大搜索到负数停止,jjj 自大至小搜索到正数停止。然后 iii 和 jjj 所指数据交换,继续以上过程,直到 i=ji=ji=j 为止。

void Arrange(int A[],int n)
//n个整数存于数组A中,本算法将数组中所有正数排在所有负数的前面
{int i=0,j=n-1,x;  //用类C编写,数组下标从0开始while(i<j){while(i<j && A[i]>0)  i++;while(i<j && A[j]<0)  j--;if(i<j) {x=A[i]; A[i++]=A[j]; A[j--]=x; }//交换A[i] 与A[j]}// while(i<j)
}//算法Arrange结束.

[算法讨论]对数组中元素各比较一次,比较次数为 nnn。最佳情况(已排好,正数在前,负数在后)不发生交换,最差情况(负数均在正数前面)发生 n/2n/2n/2 次交换。用类 ccc 编写,数组界偶是 0..n−10..n-10..n−1。空间复杂度为O(1)O(1)O(1)。


树和二叉树











以二叉链表作为二叉树的存储结构,编写以下算法:
1.统计二叉树的叶结点个数。
[题目分析]如果二叉树为空,返回 0,如果二叉树不为空且左右子树为空,返回 1,如果二叉树不为空,且左右子树不同时为空,返回左子树中叶子节点个数加上右子树中叶子节点个数。

int LeafNodeCount(BiTree T)
{if(T==NULL) return 0; //如果是空树,则叶子结点个数为0//判断结点是否是叶子结点(左孩子右孩子都为空),若是则返回1else if(T->lchild==NULL&&T->rchild==NULL) return 1; else return LeafNodeCount(T->lchild)+LeafNodeCount(T->rchild);
}

2.判别两棵树是否相等。
[题目分析]先判断当前节点是否相等(需要处理为空、是否都为空、是否相等),如果当前节点不相等,直接返回两棵树不相等;如果当前节点相等,那么就递归的判断他们的左右孩子是否相等。

int compareTree(TreeNode* tree1, TreeNode* tree2)
//用分治的方法做,比较当前根,然后比较左子树和右子树
{bool tree1IsNull = (tree1==NULL);bool tree2IsNull = (tree2==NULL);if(tree1IsNull != tree2IsNull) return 1;if(tree1IsNull && tree2IsNull){//如果两个都是NULL,则相等return 0;}//如果根节点不相等,直接返回不相等,否则的话,看看他们孩子相等不相等if(tree1->c != tree2->c){return 1;}return (compareTree(tree1->left,tree2->left)&compareTree(tree1->right,tree2->right))(compareTree(tree1->left,tree2->right)&compareTree(tree1->right,tree2->left));
}//算法结束

3.交换二叉树每个结点的左孩子和右孩子。

[题目分析]如果某结点左右子树为空,返回,否则交换该结点左右孩子,然后递归交换左右子树。

void ChangeLR(BiTree &T)
{BiTree temp;if(T->lchild==NULL&&T->rchild==NULL) return;else{temp = T->lchild;T->lchild = T->rchild;T->rchild = temp;}//交换左右孩子ChangeLR(T->lchild);  //递归交换左子树ChangeLR(T->rchild);  //递归交换右子树
}

4.设计二叉树的双序遍历算法(双序遍历是指对于二叉树的每一个结点来说,先访问这个结点,再按双序遍历它的左子树,然后再一次访问这个结点,接下来按双序遍历它的右子树)。

[题目分析]若树为空,返回;若某结点为叶子结点,则仅输出该结点;否则先输出该结点,递归遍历其左子树,再输出该结点,递归遍历其右子树。

void DoubleTraverse(BiTree T)
{if(T == NULL)return;else if(T->lchild==NULL&&T->rchild==NULL)cout<<T->data;     //叶子结点输出else{cout<<T->data;DoubleTraverse(T->lchild);   //递归遍历左子树cout<<T->data; DoubleTraverse(T->rchild);   //递归遍历右子树}
}

5.计算二叉树最大的宽度(二叉树的最大宽度是指二叉树所有层中结点个数的最大值)。

[题目分析] 求二叉树高度的算法见上题。求最大宽度可采用层次遍历的方法,记下各层结点数,每层遍历完毕,若结点数大于原先最大宽度,则修改最大宽度。

int Width(BiTree bt)//求二叉树bt的最大宽度
{if (bt==null) return (0);  //空二叉树宽度为0else {BiTree Q[];//Q是队列,元素为二叉树结点指针,容量足够大front=1;rear=1;last=1;//front队头指针,rear队尾指针,last同层最右结点在队列中的位置temp=0; maxw=0;   //temp记局部宽度, maxw记最大宽度Q[rear]=bt;           //根结点入队列while(front<=last){p=Q[front++]; temp++; //同层元素数加1if(p->lchild!=null)  Q[++rear]=p->lchild;   //左子女入队if(p->rchild!=null)  Q[++rear]=p->rchild;   //右子女入队if(front>last)      //一层结束, {last=rear;if(temp>maxw) maxw=temp;//last指向下层最右元素, 更新当前最大宽度temp=0;}//if    }//whilereturn (maxw);
}//结束width

6.用按层次顺序遍历二叉树的方法,统计树中具有度为 1 的结点数目。
[题目分析] 若某个结点左子树空右子树非空或者右子树空左子树非空,则该结点为度为 1 的结点

int Level(BiTree bt) //层次遍历二叉树,并统计度为1的结点的个数
{int num=0; //num统计度为1的结点的个数if(bt){QueueInit(Q); QueueIn(Q,bt);//Q是以二叉树结点指针为元素的队列while(!QueueEmpty(Q)){p=QueueOut(Q); cout<<p->data;     //出队,访问结点if(p->lchild && !p->rchild ||!p->lchild && p->rchild)num++;//度为1的结点if(p->lchild) QueueIn(Q,p->lchild); //非空左子女入队if(p->rchild) QueueIn(Q,p->rchild); //非空右子女入队} // while(!QueueEmpty(Q))}//if(bt)         return(num);
}//返回度为1的结点的个数

7.求任意二叉树中第一条最长的路径长度,并输出此路径上各结点的值。

[题目分析]因为后序遍历栈中保留当前结点的祖先的信息,用一变量保存栈的最高栈顶指针,每当退栈时,栈顶指针高于保存最高栈顶指针的值时,则将该栈倒入辅助栈中,辅助栈始终保存最长路径长度上的结点,直至后序遍历完毕,则辅助栈中内容即为所求。

void LongestPath(BiTree bt)//求二叉树中的第一条最长路径长度
{BiTree p=bt,l[],s[]; //l, s是栈,元素是二叉树结点指针,l中保留当前最长路径中的结点int i,top=0,tag[],longest=0;while(p || top>0){while(p) {s[++top]=p;tag[top]=0; p=p->Lc;} //沿左分枝向下if(tag[top]==1)    //当前结点的右分枝已遍历{//只有到叶子结点时,才查看路径长度if(!s[top]->Lc && !s[top]->Rc)  if(top>longest) {for(i=1;i<=top;i++) l[i]=s[i]; longest=top; top--;}//保留当前最长路径到l栈,记住最高栈顶指针,退栈}else if(top>0) {tag[top]=1; p=s[top].Rc;}   //沿右子分枝向下}//while(p!=null||top>0)
}//结束LongestPath

8.输出二叉树中从每个叶子结点到根结点的路径。

[题目分析]采用先序遍历的递归方法,当找到叶子结点 ∗b*b∗b 时,由于 ∗b*b∗b 叶子结点尚未添加到 pathpathpath 中,因此在输出路径时还需输出b−>datab->datab−>data 值。

void AllPath(BTNode *b,ElemType path[],int pathlen)
{int i;if(b!=NULL){if(b->lchild==NULL && b->rchild==NULL) //*b为叶子结点{cout <<""<< b->data << "到根结点路径:" << b->data;for (i=pathlen-1;i>=0;i--)cout << endl;}else{path[pathlen]=b->data;    //将当前结点放入路径中pathlen++;                     //路径长度增1AllPath(b->lchild,path,pathlen);   //递归扫描左子树AllPath(b->rchild,path,pathlen);   //递归扫描右子树pathlen--;                     //恢复环境}}// if (b!=NULL)
}//算法结束













1.分别以邻接矩阵和邻接表作为存储结构,实现以下图的基本操作:
① 增加一个新顶点 vvv,InsertVex(G,v)InsertVex(G, v)InsertVex(G,v);
② 删除顶点 vvv 及其相关的边,DeleteVex(G,v)DeleteVex(G, v)DeleteVex(G,v);
③ 增加一条边 <v,w><v,w><v,w>,InsertArc(G,v,w)InsertArc(G, v, w)InsertArc(G,v,w);
④ 删除一条边 <v,w><v,w><v,w>,DeleteArc(G,v,w)DeleteArc(G, v, w)DeleteArc(G,v,w)。

[算法描述] 假设图 GGG 为有向无权图,以邻接矩阵作为存储结构四个算法分别如下:

① 增加一个新顶点v

Status Insert_Vex(MGraph &G, char v)//在邻接矩阵表示的图G上插入顶点v
{if(G.vexnum+1)>MAX_VERTEX_NUM return INFEASIBLE;
G.vexs[++G.vexnum]=v;
return OK;
}//Insert_Vex

② 删除顶点v及其相关的边

Status Delete_Vex(MGraph &G,char v)//在邻接矩阵表示的图G上删除顶点v
{n=G.vexnum;if((m=LocateVex(G,v))<0) return ERROR;G.vexs[m]<->G.vexs[n]; //将待删除顶点交换到最后一个顶点for(i=0;i<n;i++){G.arcs[m]=G.arcs[n];G.arcs[m]=G.arcs[n]; //将边的关系随之交换}G.arcs[m][m].adj=0;G.vexnum--;return OK;
}//Delete_Vex

分析:如果不把待删除顶点交换到最后一个顶点的话,算法将会比较复杂,而伴随着大量元素的移动,时间复杂度也会大大增加。
③ 增加一条边<v,w>

Status Insert_Arc(MGraph &G,char v,char w)//在邻接矩阵表示的图G上插入边(v,w)
{if((i=LocateVex(G,v))<0) return ERROR;if((j=LocateVex(G,w))<0) return ERROR;if(i==j) return ERROR;if(!G.arcs[j].adj){G.arcs[j].adj=1;G.arcnum++;}return OK;
}//Insert_Arc

④ 删除一条边<v,w>

Status Delete_Arc(MGraph &G,char v,char w)//在邻接矩阵表示的图G上删除边(v,w)
{if((i=LocateVex(G,v))<0) return ERROR;if((j=LocateVex(G,w))<0) return ERROR;if(G.arcs[j].adj){G.arcs[j].adj=0;G.arcnum--;}return OK;
}//Delete_Arc

以邻接表作为存储结构,本题只给出Insert_Arc算法.其余算法类似。

Status Insert_Arc(ALGraph &G,char v,char w)//在邻接表表示的图G上插入边(v,w)
{if((i=LocateVex(G,v))<0) return ERROR;if((j=LocateVex(G,w))<0) return ERROR;p=new ArcNode;p->adjvex=j;p->nextarc=NULL;if(!G.vertices.firstarc) G.vertices.firstarc=p;else{for(q=G.vertices.firstarc;q->q->nextarc;q=q->nextarc)if(q->adjvex==j) return ERROR; //边已经存在q->nextarc=p;}G.arcnum++;return OK;
}//Insert_Arc

2.一个连通图采用邻接表作为存储结构,设计一个算法,实现从顶点v出发的深度优先遍历的非递归过程。

Void DFSn(Graph G,int v)
{  //从第v个顶点出发非递归实现深度优先遍历图 GStack s;SetEmpty(s);Push(s,v);While(!StackEmpty(s)){     //栈空时第v个顶点所在的连通分量已遍历完Pop(s,k);If(!visited[k]){  visited[k]=TRUE;VisitFunc(k);     //访问第k个顶点//将第k个顶点的所有邻接点进栈for(w=FirstAdjVex(G,k);w;w=NextAdjVex(G,k,w)){    if(!visited[w]&&w!=GetTop(s)) Push(s,w);    //图中有环时w==GetTop(s)}}}
}

3.设计一个算法,求图 G 中距离顶点v的最短路径长度最大的一个顶点,设v可达其余各个顶点。

[题目分析]利用 DijkstraDijkstraDijkstra 算法求 v0v_0v0​ 到其它所有顶点的最短路径,分别保存在数组 D[i]D[i]D[i] 中,然后求出 D[i]D[i]D[i] 中值最大的数组下标mmm 即可。

int ShortestPath_MAX(AMGraph G, int v0)
{ //用Dijkstra算法求距离顶点v0的最短路径长度最大的一个顶点m n=G.vexnum;                          //n为G中顶点的个数 for(v = 0; v<n; ++v){ //n个顶点依次初始化 S[v] = false;                          //S初始为空集 D[v] = G.arcs[v0][v];             //将v0到各个终点的最短路径长度初始化 if(D[v]< MaxInt)  Path [v]=v0;     //如果v0和v之间有弧,则将v的前驱置为v0 else Path [v]=-1;               //如果v0和v之间无弧,则将v的前驱置为-1 }//for S[v0]=true;                          //将v0加入S D[v0]=0;                              //源点到源点的距离为0 /*开始主循环,每次求得v0到某个顶点v的最短路径,将v加到S集*/ for(i=1;i<n; ++i){     //对其余n−1个顶点,依次进行计算 min= MaxInt; for(w=0;w<n; ++w) if(!S[w]&&D[w]<min)  {v=w; min=D[w];}    //选择一条当前的最短路径,终点为v S[v]=true;          //将v加入S for(w=0;w<n; ++w)   //更新从v0到V−S上所有顶点的最短路径长度 if(!S[w]&&(D[v]+G.arcs[v][w]<D[w])){ D[w]=D[v]+G.arcs[v][w];    //更新D[w] Path[w]=v;                    //更改w的前驱为v }//if }//for/*最短路径求解完毕,设距离顶点v0的最短路径长度最大的一个顶点为m */       Max=D[0];m=0;for(i=1;i<n;i++)if(Max<D[i]) m=i;        return m;
}

4.试基于图的深度优先搜索策略写一算法,判别以邻接表方式存储的有向图中是否存在由顶点vi到顶点vj的路径(iii≠jjj)。

引入一变量level来控制递归进行的层数

int visited[MAXSIZE]; //指示顶点是否在当前路径上
int level=1;//递归进行的层数
int exist_path_DFS(ALGraph G,int i,int j)//深度优先判断有向图G中顶点i到顶点j
是否有路径,是则返回1,否则返回0
{ if(i==j) return 1; //i就是j else { visited[i]=1; for(p=G.vertices[i].firstarc;p;p=p->nextarc,level--) { level++;k=p->adjvex; if(!visited[k]&&exist_path(k,j)) return 1;//i下游的顶点到j有路径 }//for }//else if (level==1)  return 0;
}//exist_path_DFS

5.采用邻接表存储结构,编写一个算法,判别无向图中任意给定的两个顶点之间是否存在一条长度为为k的简单路径。

int visited[MAXSIZE];
int exist_path_len(ALGraph G,int i,int j,int k)
//判断邻接表方式存储的有向图G的顶点i到j是否存在长度为k的简单路径
{if(i==j&&k==0) return 1; //找到了一条路径,且长度符合要求 else if(k>0) {visited[i]=1; for(p=G.vertices[i].firstarc;p;p=p->nextarc) {l=p->adjvex; if(!visited[l]) if(exist_path_len(G,l,j,k-1)) return 1; //剩余路径长度减一 }//for visited[i]=0; //本题允许曾经被访问过的结点出现在另一条路径中 }//else return 0; //没找到
}//exist_path_len

查找














1.试写出折半查找的递归算法

int  BinSrch(rectype r[ ],int  k,low,high)
//在长为n的有序表中查找关键字k,若查找成功,返回k所在位置,查找失败返回0。
{if(low≤high)  //low和high分别是有序表的下界和上界{mid =(low+high)/2;if(r[mid].key==k) return (mid);else if(r[mid].key>k) return  (BinSrch(r,k,mid+1,high));else return (BinSrch(r,k,low,mid-1));}else  return (0);//查找失败。
}//算法结束

2.试写一个判别给定二叉树是否为二叉排序树的算法。

[题目分析] 根据二叉排序树中序遍历所得结点值为增序的性质,在遍历中将当前遍历结点与其前驱结点值比较,即可得出结论,为此设全局指针变量 preprepre(初值为 nullnullnull)和全局变量 flagflagflag,初值为 truetruetrue。若非二叉排序树,则置 flagflagflag 为 falsefalsefalse。

#define true 1
#define false 0
typedef struct node
{datatype data; struct node *lchild,*rchild;
} *BTree;
void  JudgeBST(BTree T,int  flag)
// 判断二叉树是否是二叉排序树,本算法结束后,在调用程序中由flag得出结论。
{ if(T!=null && flag){ Judgebst(T->lchild,flag); // 中序遍历左子树if(pre==null) pre=T;// 中序遍历的第一个结点不必判断else  if(pre->data<T->data) pre=T;//前驱指针指向当前结点else{ flag=flase; }   //不是完全二叉树 Judgebst(T->rchild,flag); // 中序遍历右子树
}//JudgeBST算法结束

3.已知二叉排序树采用二叉链表存储结构,根结点的指针为 TTT,链结点的结构为 (lchild,data,rchild)(lchild,data,rchild)(lchild,data,rchild) ,其中 lchildlchildlchild,rchildrchildrchild 分别指向该结点左、右孩子的指针,datadatadata 域存放结点的数据信息。请写出递归算法,从小到大输出二叉排序树中所有数据值 >=x>=x>=x 的结点的数据。要求先找到第一个满足条件的结点后,再依次输出其他满足条件的结点。

[题目分析]本题算法之一是如上题一样,中序遍历二叉树,在“访问根结点”处判断结点值是否≥x,如是则输出,并记住第一个≥x值结点的指针。这里给出另一个算法,利用二叉排序树的性质,如果根结点的值>=x,则除左分枝中可能有<x的结点外都应输出。所以从根结点开始查找,找到结点值<x的结点后,将其与双亲断开输出整棵二叉排序树。如果根结点的值<x,则沿右子树查找第一个≥x的结点,找到后,与上面同样处理。

void  Print(BSTree  t)// 中序输出以t为根的二叉排序树的结点
{if(t){Print(t->lchild);Cout<<t-data;Print(t->rchild);}
}
void  PrintAllx(BSTree bst,datatype x)//在二叉排序树bst中,查找值≥x的结点并输出
{p=bst;if(p){while(p && p->data<x)p=p->rchild;//沿右分枝找第一个值≥x的结点bst=p; //bst所指结点是值≥x的结点的树的根if(p){f=p; p=p->lchild; //找第一个值<x的结点while(p && p->data≥x)//沿左分枝向下,找第一个值<x的结点{f=p;p=p->lchild;} //f是p的双亲结点的指针,指向第一个值≥x的结点if(p) f->lchild=null; //双亲与找到的第一个值<x的结点断开
Print(bst);//输出以bst为根的子树}//while}//内层if(p)}//第一层if(p)
}//PrintAllx

4.已知二叉树 TTT 的结点形式为(llingllinglling, datadatadata, countcountcount, rlinkrlinkrlink),在树中查找值为 XXX 的结点,若找到,则记数(countcountcount)加1,否则,作为一个新结点插入树中,插入后仍为二叉排序树,写出其非递归算法。

void SearchBST(BiTree &T,int target)
{BiTree s,q,f;  //以数据值target,新建结点ss=new BiTNode;s->data.x=target;s->data.count=0;s->lchild=s->rchild=NULL;if(!T){T=s;return ;}   //如果该树为空则跳出该函数f=NULL;q=T;while (q){if (q->data.x==target){q->data.count++;return ;}  //如果找到该值则计数加一f=q;if (q->data.x>target)   //如果查找值比目标值大,则为该树左孩子q=q->lchild;else     //否则为右孩子q=q->rchild;}  //将新结点插入树中if(f->data.x>target)f->lchild=s;elsef->rchild=s;
}

5.假设一棵平衡二叉树的每个结点都表明了平衡因子 bbb,试设计一个算法,求平衡二叉树的高度。

[题目分析] 因为二叉树各结点已标明了平衡因子 bbb,故从根结点开始记树的层次。根结点的层次为 1,每下一层,层次加 1,直到层数最大的叶子结点,这就是平衡二叉树的高度。当结点的平衡因子 bbb 为0时,任选左右一分枝向下查找,若 bbb 不为0,则沿左(当 bbb = 1时)或右(当 bbb = -1时)向下查找。

int   Height(BSTree t) // 求平衡二叉树t的高度
{level=0;p=t;while(p){level++; // 树的高度增1if(p->bf<0)p=p->rchild;//bf=-1 沿右分枝向下
//bf是平衡因子,是二叉树t结点的一个域,因篇幅所限,没有写出其存储定义else p=p->lchild;        //bf>=0 沿左分枝向下}//whilereturn  (level);//平衡二叉树的高度
} //算法结束

6.分别写出在散列表中插入和删除关键字为 KKK 的一个记录的算法,设散列函数为 HHH,解决冲突的方法为链地址法。

bool insert(){int data;cin>>data;int ant=hash(data);LinkList p=HT[ant];   //初始化散列表while (p->next){if(p->next->data==data)return false;   p=p->next;}   //找到插入位置LinkList s;s=new LNode;s->data=data;s->next=p->next;p->next=s;  //插入该结点return true;
}bool deletes(){int data;cin>>data;int ant=hash(data);LinkList p=HT[ant];  //初始化散列表while (p->next){if(p->next->data==data){LinkList s=p->next;p->next=s->next;delete s;  //删除该结点return true;}  //找到删除位置p=p->next; //遍历下一个结点}return false;
}

排序




①直接插入排序
[2    12]   16   30   28   10   16*   20   6    18
[2    12    16]  30   28   10   16*   20   6    18
[2    12    16   30]  28   10   16*   20   6    18
[2    12    16   28   30]  10   16*   20   6    18
[2    10    12   16   28  30]   16*   20   6    18
[2    10    12   16   16*  28   30]   20   6    18
[2    10    12   16   16*  20   28   30]   6    18
[2    6     10   12   16  16*   20   28   30]   18
[2    6     10   12   16  16*    18   20   28   30]
② 折半插入排序 排序过程同①
③ 希尔排序(增量选取5,3,1)
10   2    16   6    18   12   16*   20  30    28 (增量选取5)
6    2    12   10   18   16   16*   20  30    28 (增量选取3)
2    6    10   12   16   16*  18      20  28    30 (增量选取1)④ 冒泡排序
2    12   16    28   10   16*  20   6     18   [30]
2    12   16    10   16*  20   6    18    [28   30]
2    12   10    16   16*  6     18   [20   28   30]
2    10   12    16   6   16*    [18   20   28   30]
2    10   12    6   16   [16*    18   20   28   30]
2    10   6    12   [16   16*    18   20   28   30]
2    6   10    [12   16   16*    18   20   28   30]
2    6   10    12   16   16*    18   20   28   30]
⑤ 快速排序
12  [6    2  10]  12  [28  30  16*  20   16  18]
6   [2]  6   [10]  12  [28  30  16*  20   16  18 ]
28  2    6   10   12  [18  16  16*  20 ] 28  [30 ]
18  2   6   10  12   [16*  16]  18  [20]  28  30
16*     2   6   10  12   16* [16]   18  20   28  30
左子序列递归深度为1,右子序列递归深度为3
⑥ 简单选择排序
2    [12   16   30   28   10   16*   20   6    18]
2    6    [16   30   28   10   16*   20   12   18]
2    6    10   [30   28   16   16*   20   12   18]
2    6    10   12   [28   16   16*   20   30   18]
2    6    10   12   16   [28   16*   20   30   18]
2    6    10   12   16   16*    [28  20   30   18]
2    6    10   12   16   16*   18   [20   30   28]
2    6    10   12   16   16*   18    20   [28  30]
2    6    10   12   16   16*    18   20   28   [30]⑧ 二路归并排序
2 12    16 30    10 28    16 * 20    6 18
2 12 16 30        10 16* 20 28       6 18
2 10 12 16 16* 20 28 30   6 18
2 6 10 12 16 16* 18 20 28 30



1.试以单链表为存储结构,实现简单选择排序算法。

void LinkedListSelectSort(LinkedList head)
//本算法一趟找出一个关键字最小的结点,其数据和当前结点进行交换;若要交换指针,则须记下
//当前结点和最小结点的前驱指针
{p=head->next; while(p!=null){q=p->next;  r=p;    //设r是指向关键字最小的结点的指针while (q!=null){if(q->data<r->data) r=q;q=q->next;}if(r!=p)  r->data<-->p->data;p=p->next;}
}

2.有 nnn 个记录存储在带头结点的双向链表中,现用双向冒泡排序法对其按上升序进行排序,请写出这种排序的算法。(注:双向冒泡排序即相邻两趟排序向相反方向冒泡)。

typedef struct node
{ ElemType data;struct node *prior,*next;
}node,*DLinkedList;
void  TwoWayBubbleSort(DLinkedList la)
//对存储在带头结点的双向链表la中的元素进行双向起泡排序。
{int exchange=1;  // 设标记 DLinkedList p,temp,tail;head=la         //双向链表头,算法过程中是向下起泡的开始结点tail=null;      //双向链表尾,算法过程中是向上起泡的开始结点while(exchange){p=head->next;    //p是工作指针,指向当前结点exchange=0;      //假定本趟无交换 while (p->next!=tail)  // 向下(右)起泡,一趟有一最大元素沉底if (p->data>p->next->data) //交换两结点指针,涉及6条链{temp=p->next; exchange=1;//有交换p->next=temp->next;temp->next->prior=p //先将结点从链表上摘下temp->next=p; p->prior->next=temp;     //将temp插到p结点前temp->prior=p->prior;p->prior=temp;}else p=p->next; //无交换,指针后移tail=p; //准备向上起泡p=tail->prior;while (exchange && p->prior!=head)  //向上(左)起泡,一趟有一最小元素冒出if (p->data<p->prior->data)       //交换两结点指针,涉及6条链{temp=p->prior; exchange=1;     //有交换p->prior=temp->prior;temp->prior->next=p; //先将temp结点从链表上摘下temp->prior=p; p->next->prior=temp; //将temp插到p结点后(右)temp->next=p->next; p->next=temp;}else p=p->prior;  //无交换,指针前移head=p;             //准备向下起泡}// while (exchange)
} //算法结束

3.设有顺序放置的n个桶,每个桶中装有一粒砾石,每粒砾石的颜色是红,白,蓝之一。要求重新安排这些砾石,使得所有红色砾石在前,所有白色砾石居中,所有蓝色砾石居后,重新安排时对每粒砾石的颜色只能看一次,并且只允许交换操作来调整砾石的位置。

[题目分析]利用快速排序思想解决。由于要求“对每粒砾石的颜色只能看一次”,设3个指针 iii, jjj 和 kkk,分别指向红色、白色砾石的后一位置和待处理的当前元素。从 kkk = nnn 开始,从右向左搜索,若该元素是兰色,则元素不动,指针左移(即 k−1k-1k−1);若当前元素是红色砾石,分 iii >= jjj(这时尚没有白色砾石)和 iii < jjj 两种情况。前一情况执行第i个元素和第 kkk 个元素交换,之后 iii +1;后一情况,iii 所指的元素已处理过(白色),jjj 所指的元素尚未处理,应先将 iii 和 jjj 所指元素交换,再将 iii 和 kkk 所指元素交换。对当前元素是白色砾石的情况,也可类似处理。
为方便处理,将三种砾石的颜色用整数1、2和3表示。

void QkSort(rectype r[],int n)
{// r为含有n个元素的线性表,元素是具有红、白和兰色的砾石,用顺序存储结构存储,
//本算法对其排序,使所有红色砾石在前,白色居中,兰色在最后。int i=1,j=1,k=n,temp;while (k!=j){while (r[k].key==3) k--;// 当前元素是兰色砾石,指针左移 if (r[k].key==1)        // 当前元素是红色砾石if (i>=j){temp=r[k];r[k]=r[i];r[i]=temp; i++;}
//左侧只有红色砾石,交换r[k]和r[i]else     {temp=r[j];r[j]=r[i];r[i]=temp; j++;  //左侧已有红色和白色砾石,先交换白色砾石到位 temp=r[k];r[k]=r[i];r[i]=temp; i++;
//白色砾石(i所指)和待定砾石(j所指)}   //再交换r[k]和r[i],使红色砾石入位。if (r[k].key==2)if (i<=j) {temp=r[k];r[k]=r[j];r[j]=temp; j++;}
// 左侧已有白色砾石,交换r[k]和r[j] else { temp=r[k];r[k]=r[i];r[i]=temp; j=i+1;}
//i、j分别指向红、白色砾石的后一位置}//whileif (r[k]==2) j++;   /* 处理最后一粒砾石else if (r[k]==1) { temp=r[j];r[j]=r[i];r[i]=temp; i++; j++; }//最后红、白、兰色砾石的个数分别为: i-1;j-i;n-j+1
}//结束QkSor算法
[算法讨论]若将j(上面指向白色)看作工作指针,将r[1..j-1]作为红色,r[j..
k-1]为白色,r[k..n]为兰色。从j=1开始查看,若r[j]为白色,则j=j+1;若r[j]
为红色,则交换r[j]与r[i],且j=j+1,i=i+1;若r[j]为兰色,则交换r[j]与r[k];
k=k-1。算法进行到j>k为止。
算法片段如下:
int i=1,j=1,k=n;
while(j<=k)if (r[j]==1)  //当前元素是红色{temp=r[i]; r[i]=r[j]; r[j]=temp; i++;j++; }else if (r[j]==2) j++;  //当前元素是白色
else               //(r[j]==3  当前元素是兰色{temp=r[j]; r[j]=r[k]; r[k]=temp; k--; }
对比两种算法,可以看出,正确选择变量(指针)的重要性。

4.编写算法,对 nnn 个关键字取整数值的记录序列进行整理,以使所有关键字为负值的记录排在关键字为非负值的记录之前,要求:
① 采用顺序存储结构,至多使用一个记录的辅助存储空间;
② 算法的时间复杂度为 O(n)O(n)O(n)。

void  process (int A[n])
{low = 0;high = n-1;while ( low<high ){while (low<high && A[low]<0)low++;while (low<high && A[high]>0)high++;if (low<high){   x=A[low];A[low]=A[high];A[high]=x;low++;high--;}}return;
}

5.借助于快速排序的算法思想,在一组无序的记录中查找给定关键字值等于keykeykey 的记录。设此组记录存放于数组 r[l..n]r[l..n]r[l..n] 中。若查找成功,则输出该记录在 rrr 数组中的位置及其值,否则显示 “not“not“not find”find”find” 信息。请简要说明算法思想并编写算法。

题目分析]把待查记录看作枢轴,先由后向前依次比较,若小于枢轴,则从前向后,直到查找成功返回其位置或失败返回0为止。

int index (RecType R[],int l,h,datatype key)
{int i=l,j=h;while (i<j){ while (i<=j && R[j].key>key) j--;if (R[j].key==key) return  j;while (i<=j && R[i].key<key) i++;if (R[i].key==key) return  i;}cout<<“Not find”; return  0;
}//index

6.有一种简单的排序算法,叫做计数排序。这种排序算法对一个待排序的表进行排序,并将排序结果存放到另一个新的表中。必须注意的是,表中所有待排序的关键字互不相同,计数排序算法针对表中的每个记录,扫描待排序的表一趟,统计表中有多少个记录的关键字比该记录的关键字小。假设针对某一个记录,统计出的计数值为 ccc,那么,这个记录在新的有序表中的合适的存放位置即为 ccc。
① 给出适用于计数排序的顺序表定义;
② 编写实现计数排序的算法;
③ 对于有 nnn 个记录的表,关键字比较次数是多少?
④ 与简单选择排序相比较,这种方法是否更好?为什么?

① typedef struct
{int key; datatype info
}RecType
② void CountSort(RecType a[],b[],int n)
//计数排序算法,将a中记录排序放入b中
{for(i=0;i<n;i++) //对每一个元素{for(j=0,cnt=0;j<n;j++)if(a[j].key<a[i].key) cnt++; //统计关键字比它小的元素个数b[cnt]=a[i];}
}//Count_Sort
③ 对于有n个记录的表,关键码比较n2次。
④ 简单选择排序算法比本算法好。简单选择排序比较次数是n(n-1)/2,且只用一个交换记录的空间;而这种方法比较次数是n2,且需要另一数组空间。
[算法讨论]因题目要求“针对表中的每个记录,扫描待排序的表一趟”,所以比较次数是n2次。若限制“对任意两个记录之间应该只进行一次比较”,则可把以上算法中的比较语句改为:
for(i=0;i<n;i++) a[i].count=0;//各元素再增加一个计数域,初始化为0
for(i=0;i<n;i++)for(j=i+1;j<n;j++) if(a[i].key<a[j].key) a[j].count++; else a[i].count++;

小结

数据结构课后题的截图,方便查阅,不能运行请见谅,本蒟蒻 C++C++C++ 版本的数据结构代码可私聊本蒟蒻,伸手党勿扰!

数据结构 严蔚敏 习题总结相关推荐

  1. 构建线性表的c语言代码,数据结构严蔚敏C语言版—线性表顺序存储结构(顺序表)C语言实现相关代码...

    1.运行环境 这里说明一下这里所有的C语言代码都是基于code::blocks 20.03编译运行的.当然一些其他集成开发环境应该也是可以的,个人不太喜欢功能太过强大的IDE,因为那同样意味着相关设置 ...

  2. 数据结构 严蔚敏 第二章 线性表

    数据结构 严蔚敏 第二章 线性表 线性表:由n个(n>=0)数据特征相同的元素构成的有限序列. 线性表的类型定义表示和实现 顺序表 存储单元地址连续 随机存取 若每个元素占用 m 个存储单元,以 ...

  3. 【计算机】数据结构-严蔚敏/清华大学P3

    [计算机]数据结构-严蔚敏/清华大学P1 第二章    线  性表 线性结构 是 一个数据元素的有序(次序)集 线性结构的基本特征: 1.  集合中必存在唯一的一个"第一元素": ...

  4. 数据结构严蔚敏C语言版—线性表顺序存储结构(顺序表)C语言实现相关代码

    数据结构严蔚敏C语言版-线性表顺序存储结构(顺序表)C语言实现相关代码 1.运行环境 2.准备工作 1)项目构建 1>新建一个SeqList项目 2>新建两个文件Sources和Heade ...

  5. 数据结构----严蔚敏

    最近一直想找一本纯数据结构的书来学习,找来找去都没有找到一本合适的书籍,相比之下国内的书籍之中,严蔚敏和吴伟民的还算是经典版了,很多国内其他数据结构教材都参考这本书的.但缺点是很多都是伪代码,对编程初 ...

  6. 数据结构严蔚敏清华大学pdf_2019年清华大学自动化系控制工程专业大数据方向考研经验分享...

    基本情况(以下内容仅代表个人观点) 我目前就读于西南某双非石油工程专业,2019考研报考清华大学自动化系大数据工程专业,一志愿复试被刷,侥幸调剂录取至微电子系.初试总分346分(政治-63 + 英语一 ...

  7. 数据结构(严蔚敏版)习题集第三章课后标新号习题答案

    #include<iostream> #include<cctype> using namespace std; /****预定义****/ #define STACK_INI ...

  8. 有关数据结构基础知识(数据结构 严蔚敏版)

    1. 数据结构是一门研究非数值计算程序设计中的操作对象 以及这些对象之间的关系和操作的学科 2. 研究包括逻辑结构和存储结构 1) 逻辑结构(从具体问题抽象出来的数学模型)分为 集合结构 线性结构 树 ...

  9. 数据结构----严蔚敏 (链表)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.链表是什么? 二.使用步骤 总结 前言 数据结构是软件技术.网络技术等计算机类专业的一门重要的专业基础课程,其理论 ...

  10. 字符串静态顺序结构C/C++实现(数据结构严蔚敏版)

    1.头文件String.h #include<stdio.h> #include<stdlib.h> #include<string.h> #include< ...

最新文章

  1. 无事“自动驾驶”,有事“辅助驾驶”?
  2. 宝塔面板遇到No space left on device错误的解决方法
  3. 日常工作问题解决:配置NTP服务器以及一些常见错误解决
  4. 有选择性的启用SAP UI5调试版本的源代码
  5. git强行让本地分支覆盖远程分支
  6. Python 函数的执行流程-函数递归-匿名函数-生成器
  7. python打印长方形_利用python打印出菱形、三角形以及矩形的方法实例
  8. 智能会议系统(2)---Android 2.3 APIs SIP-based VoIP
  9. Nest.js 管道
  10. Hadoop学习笔记(一):MapReduce工作机制
  11. 第三季-第20课-多线程程序设计
  12. STA series --- 3.Standard cell library(PART-III)
  13. 优化后亲测可用!免费下载QQ音乐大部分资源
  14. 什么是脏数据,缓存中是否可能产生脏数据,如果出现脏数据该怎么处理?
  15. 传统车载网络,软件定义汽车
  16. win10磁盘分区合并(win10磁盘分区合并c盘时扩展卷点不开)
  17. 有限域GF(2^8).md
  18. Java 全栈知识体系
  19. mysql创建前缀索引
  20. 安徽大学计算机专业参考书目,安徽大学计算机科学与技术(专业学位)考研参考书目...

热门文章

  1. 国产企业级服务器操作系统排名,国产操作系统那个最好排名
  2. ssl教程易语言代码
  3. 易语言程序转c语言,C语言转易语言代码工具下载
  4. sql格式化工具-SQL Pretty Printer
  5. USB加密狗复制克隆软件
  6. regexp(正则表达式)的使用
  7. 中信所怎么查期刊影响因子_《2019年版中国科技期刊引证报告(核心版)自然科学卷》医学类期刊目录(附影响因子)...
  8. 传奇游戏源码 Linux版本
  9. matlab定积分上界求解,定积分问题的数值求解及Matlab实现
  10. python怎么通过手机号定位_基于Python的免费手机号码归属地查询