1、元素逆置
方法一:给定一个字符串C=“a0a1……an-1an”,其采用顺序队列结构存储,现需要将其逆序,即变换成“anan-1……a1a0”,变换后的结果仍然存储在原队列中。若给定一个顺序栈作为辅助结构,请给出实现策略。
1. 元素逆置://顺序的入栈
2. for(i = 0;i < n;i++)
3. {
4. scanf("%d",&a);
5. Push(&s,a);
6. }
7.
8. int stackNumber;
9. for(i=0;i<n;i++)
10. {
11. Pop(&s,&stackNumber); //逆序的出栈(遵顼先进后出原则)
12. EnQueue(&q,stackNumber);//逆序的入队
13. }
方法二:单链表
拟采用带头结点的单链表来存储线性表中的数据元素,但要求单链表中数据元素的存储顺序与线性表中数据元素的顺序逆序。即若线性表中的数据元素序列是a1,a2,……, an-1,an,则实现的单链表的数据元素的序列是an,an-1, ……,a2,a1
node *reverse(node *head)//链表的逆置
{
node *next;
node *prev = NULL;//prev指向逆置前的一个结点
while (head != NULL)
{
next = head->next;//指向头结点的下一个结点
head->next = prev;//逆向修改指针
prev = head;//继续移动
head = next; //继续移动
}
return prev;
}
2、求众数
请设计一个有效的算法,在10万个顺序存储的数据元素集合(无序存储)中找出众数。
3、
一元稀疏多项式以循环单链表按降幂排列,结点有三个域,系数域coef ,指数域exp和指针域next;现对链表求一阶导数 ,链表的头指针为ha,头结点的exp域为 –1。
derivative(ha)
{ q=ha ; pa=ha->next;
while( pa->exp!=-1)
{ if ( pa->exp==0) { //若指数为0,即本项为常数项
(q->next=pa->next); //删常数项
free(pa);
pa= ( q-next); } //取下一元素
else{
pa->coef =pa->coef*pa->exp;
pa->exp--; //指数项减1
q=pa;} //前驱后移,或q->next
pa=pa->next;//取下一指针
}
}
4、对单链表中元素按插入方法排序的C语言描述算法如下,其中L为链表头结点指针。?
typedef struct node
{int data; struct node *next;
}linknode,*link;
void Insertsort(link L)
{ link p,q,r,u;
p=L->next;
L->next==NULL;//置空链表,然后将原链表结点逐个插入到有序表中
while(p!=NULL)//当链表尚未到尾,p为工作指针
{
r=L;
q=L->next;
while(q!=NULL && q->data<=p->data) //查p结点在链表中的插入位置,这时q是工作指针
//此段代码表示顺序时不需要进行结点的调整
{
r=q;
q=q->next;
}
u=p->next;
p->next=r->next;//将p结点链入链表中
r->next=p;//r是q的前驱,u是下个待插入结点的指针
p=u;
}
5、假设有两个按元素值递增次序排列的线性表,均以单链表形式存储。请编写算法将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表。(两递增合成一个递减)
void MergeList(Linklist& la,Linklist& lb,Linklist& lc){
pa=la->next;
pb=lb->next;
lc=pc=la;
lc->next=NULL;
while(pa||pb){
if(!pa){//只要存在一个非空表,用pc指向待摘取元素
pc=pa;
pa=pa->next;
}
else if(!pb){
pc=pb;
pb=pb->next;
}
else if(pa->data <=pb->data){//取较小者(包括相等),pc指向pa,pa后移
pc=pa;
pa=pa->next;
}
else {
pc=pb;
pb=pb->next;
}
pc->next=lc->next;
lc->next=pc;//将pc指向的结点插在lc的头结点之后
delete(lb);//释放lb的头结点
}
}
另:顺序表:线性表顺序LA,LB元素按非递减有序,将LB合并到LA中,LA保持非递减有序,最大限度的避免移动元素(两递增合成一个递增,顺序表)
1 k=m+n-1;i=m-1;j=n-1;
2 while(i>=0&&j>=0){
3 if(LA[i]>=LB[j])
LA[k--]=LA[i--];
else LA[k--]=LB[j--];
4 }
5 while(j>=0) LA[k--]=LB[j--];
6、设有两个无头结点的单链表,头指针分别为ha,hb,链中有数据域data,链域next,两链表的数据都按递增序存放,现要求将hb表归到ha表中,且归并后ha仍递增序,归并中ha表中已有的数据若hb中也有,则hb中的数据不归并到ha中,hb的链表在算法中不允许破坏。(两递增合成一个递增,不允许LB被破坏)
//[问题分析]与上题类似,不同之处在于:一是链表无头结点,为处理方便,给加上头结点,处理结束再删除之;二是数据相同的结点,不合并到结果链表中;三是hb链表不能被破坏,即将hb的结点合并到结果链表时,要生成新结点。
LinkedList Union(LinkedList ha, hb){
//ha和hb是两个无头结点的数据域值递增有序的单链表,本算法将hb中并不出现在ha中的数据合并到ha中,合并中不能破坏hb链表。
LinkedList la;
la=(LinkedList)malloc(sizeof(LNode));
la->next=ha;//申请头结点,以便操作。
pa=ha;//pa是ha链表的工作指针
pb=hb;//pb是hb链表的工作指针
pre=la;//pre指向当前待合并结点的前驱。
while(pa && pb){
if(pa->data < pb->data){ //处理ha中数据
pre->next=pa;
pre=pa;
pa=pa->next;
}
else if(pa->data>pb->data){//处理hb中数据。
r=(LinkedList)malloc(sizeof(LNode));//申请空间
r->data=pb->data;//将新结点链入结果链表。
pre->next=r;
pre=r;
pb=pb->next; //hb链表中工作指针后移。
}
else{//处理pa->data=pb->data;
pre->next=pa;
pre=pa;//两结点数据相等时,只将ha的数据链入。
pa=pa->next;
pb=pb->next; //不要hb的相等数据
}
if(pa){//将两链表中剩余部分链入结果链表。
pre->next=pa;
}
else{
pre->next=pb;
}
}
free(la);//释放头结点.ha,hb指针未被破坏。
}//算法nion结束。
7、将两个递增有序链表合并成一个递增有序链表,要求不另外使用空间,表中不允许出现重复元素。(两递增合成一个递增,允许LB被破坏)
void Mergelist(linklist &la,linklist &lb,linklist &lc){
pa=la->next;
pb=lb->next;
lc=pc=la;//la的头结点作为lc的头结点
while(pa&&pb){
if(pa->data < pb->data){
pc->next=pa;
pc=pa;
pa=pa->next;
}
else if(pa->data > pb->data){
pc->next=pb;
pc=pb;
pb=pb->next;
}
else{//相等时取la元素,删除lb中重复元素
pc->next=pa;
pc=pa;
pa=pa->next;
q=pb->next;//记录pb的下一个指针
delete pb;
pb=q;
}
}
if(pa) pc->next=pa;//插入剩余段
else pc-next=pb;
delete lb;
}
8、两递增链表A、B,求A、B的交集,并把结果存在A中。
void Mix(linklist &la,linklist &lb,linklist &lc){
pa=la->next;
pb=lb->next;
lc=pc=pa;
while(pa&&pb){
if(pa->data=pb->data){//交集并入结果链表中
pc->next=pa;
pc=pa;
pa=pa->next;
u=pb;//删除pb元素
pb=pb->next;
delete(u);
}
else if(pa->data<pb->data){
u=pa;//删除pa元素
pa=pa->next;
delete(u);
}
else{
u=pa;//删除pa元素
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头结点
}
9、两递增链表A、B,求A、B的差集(在A出现而不在B出现),并把结果存在A中,同时放回该集合的元素个数。
void Difference(linklist &la,linklist &lb,int *n){//*n是结果集合中元素的个数,调用时为0
pa=la->next;
pb=lb->next;
pre=la;//pre为pa所指结点的前驱结点
while(pa&&pb){
if(pa->data=pb->data){//出现相同元素则把相同元素删除
pre->next=pa->next;
u=pa;//删除pa结点
pa=pa->next;
delete(u);
}
else if(pa->data<pb->data){//A链表中当前结点指针后移
pre=pa;
pa=pa->next;
*n++;
}
else{
u=pb;//删除pa元素
pb=pb->next;
delete(u);
}
}
}
10、A链表分解为B、C两个链表,B中结点为A中小于0的结点,C中结点为A中大于0的结点。
void Mix(linklist &la,linklist &lb,linklist &lc){
pa=la->next;
pb=lb->next;
pc=lc->next;
while(pa&&pb){
if(pa->data<0){//链入B中
pb->next=pa;
pb=pa;
pa=pa->next;
}
else {//链入C中
pc->next=pa;
pc=pa;
pa=pa->next;
}
}
}
11、通过一趟遍历在单链表中确定值最大的结点
void max(linklist L){
p=L->next;
r=L->next;
while(p){
if(p->data<pa->next->data){
r=p->next;
}
else{
p=p->next;
}
}
return r->data;
}
12、遍历一遍,将链表中所有结点逆置,利用原表空间。
void inverse(Linklist &L){
p=L->next;
L->next=NULL;
while(p){
q=p->next;//q指向p的后继结点
p->next=L->next;
L->next=p;//q插在头结点之后
p=q;
}
}
13、删除递增有序链表中值大于mink且小于maxk的所有元素。(mink和maxk是给定的两个参数,其值任意)
void delete(LinkList&L,int mink,int maxk){
p=L->next;//p指向首元结点
while(p&& p->data<=mink){//查找第一个值>mink
pre=p;
p=p->next;
}
if(p){//防止前面一个出现没有符合题意的值而继续
while(p&p->data<maxk){//查找第一个值>=maxk
p=p->next;
}
}
r=pre->next;
pre->next=p;//修改指针
p->next=NULL;
while(r!=p){//释放结点空间
q=r->next;
delete(r);
r=p;
}
}
14、已知循环双链表L,写出算法change§,交换p所指向的结点和p的前缀结点,其结点结构为data,prior,next三个域。
void change(Linkedlist p){
q=p->llink;
q->llink->rlink=p;
p->llink=q->llink;
q->rlink=p->rlink;
q->llink=p;//首先处理q的四个链
p->rlink->llink=q;
p->rlink=q;
}
15、长度为n的线性表A采用顺序存储结构。写一时间复杂度为O(n),空间复杂度为O(1)的算法,删除线性表中所有值为item的数据元素。
顺序表上的删除会涉及i+1到n元素的移动,设置两个指针比较方便。
void delete(Elemtype A[],int n){
int i=1;
int j=n;
while(i<j){
while(i<j&&A[i]!=item){
i++
}
while(i<j&&A[j]==item){
j--;
}
if(i<j) A[i++]=A[j--];//万一最后一个元素是item呢?
}
}
16、统计二叉树的叶结点个数
int LeafNodeCount(BiTree T){
while(T){
if(T==NULL) renturn 0;
else if(T->lchild==NULL && T->rchild==NULL) return 1;
else return LeafNodeCount(T->lchild)+LeafNodeCount(T->rchild);
}
}
17、判别两颗树是否相等
bool check(BiTNode *T1,BiTNode *T2)
{
if(!T1 && !T2) //T1和T2都为空?
return true;
if(!T1 || !T2) //T1,T2有一颗为空,一颗不为空?
return false;
if(T1 && T2)
{
if(T1->data != T2->data)
return false;
bool l=check(T1->lchild,T2->lchild);
bool r=check(T1->rchild,T2->rchild);
return l && r;
}
}
18、交换二叉树每个结点的左孩子和右孩子
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);
}
19、二叉树的双序遍历算法
void DoubleTraverse(Bitree T){
if(T==NULL) return;
else if(T->lchild==NULL&&T->rchild==NULL)
printf("%c",T->data);//叶子结点的输出
else{
printf("%c",T->data);
DoubleTraverse(T->lchild);//递归遍历左子树
printf("%c",T->data);
DoubleTraverse(T->rchild);//递归遍历右子树
}
}
20、计算二叉树的最大宽度
采用层次遍历法,记下各层的结点数,每层遍历完毕,若结点数大于原先最大宽度,则修改最大宽度。
int Width(Bitree bt){
if(bt==NULL) return(0);//空二叉树宽度为0
else{
Bitree Q[];//Q是队列,元素为二叉树结点的指针,容量足够大
front=1;rear=1;last=1;//对头指针、队尾指针、last为最右结点在队列中的位置
temp=0;maxw=0; //temp记局部宽度,maxw记最大宽度
Q[rear]=bt; //根结点入队
while(front<=last){
p=Q[front++];
temp++; //同层元素加一
if(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;
}
}
return (maxw);
}
}
21、用层次遍历二叉树,统计树中度为一的结点数目。
若某个结点左子树空右子树非空或者右子树空左子树非空,则该结点为度为1的结点。
void QueueInit(SeQueue &Q)
{
Q.front = Q.rear = 0;//队头和队尾相等即为空队列
}
void QueueIn(SeQueue &Q,BiTree x)
{
if( (Q.rear+1) % MAX == Q.front )//入队必须判断队列是否满了
printf("Queue full\n");
Q.rear = (Q.rear+1) % MAX;
Q.data[Q.rear] = x;
}
BiTree QueueOut(SeQueue &Q)
{
if(Q.rear == Q.front) //出队列时候必须判断队列是否为空
printf("Queue empty\n");
BiTree x;
Q.front = (Q.front+1) % MAX;
x = Q.data[Q.front];
return x;
}
int QueueEmpty(SeQueue Q)
{
return (Q.front==Q.rear);
}
int Level(BiTree bt) //层次遍历二叉树,并统计度为1的结点的个数
{
BiTree p;
SeQueue Q;
int num=0; //num统计度为1的结点的个数
if(bt)
{
QueueInit(Q);
QueueIn(Q,bt);//Q是以二叉树结点指针为元素的队列
while(!QueueEmpty(Q))
{
p=QueueOut(Q);
printf("%c ",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的结点的个数
}
22、求任意二叉树中第一条最长的路径长度,并输出此路径上各结点的值。
递归
int Depth(BiTree T)/* 深度 */
{
if(T==NULL)
return(0);
return 1+(Depth(T->lchild)>Depth(T->rchild)?Depth(T>lchild):Depth(T->rchild));
//选择左右孩子深度高的然后加上根节点这一层就是深度了
}
void Long(BiTree T)
{
if(T!=NULL)//在T不为空的情况下
{
visit(T->data);//访问节点
if(Depth(T->lchild)>Depth(T->rchild))//判断往左走还是往右走
Long(T->lchild);
else
Long(T->rchild);
}
}
//深度就是长度,下面的函数要调用上面的函数
23、输出二叉树中每个叶子结点到根结点的路径。
递归
void Allpath2(BTNode *b,ElemType path[],int pathlen)
{ //先序遍历方法输出每个叶子结点到根结点的路径序列
if(b!=NULL)
{ if (b->lchild==NULL && b->rchild==NULL) //b为叶子
{ //输出栈中所有结点值
printf("%c->",b->data);
for (int i=pathlen-1;i>0;i--)
printf("%c->",path[i]);
printf("%c\n",path[0]);
}
else
{ path[pathlen++]=b->data;
Allpath2(b->lchild, path, pathlen);
Allpath2(b->rchild, path, pathlen);
}
}
}
24、深度优先遍历算法。
递归:
void PreorderRecursive(Bitree root){
if (root) {
visit(root);
PreorderRecursive(root->lchild);
PreorderRecursive(root->rchild);
}
}
非递归(栈):
void pre(Bitree root){
stack stk;//声明一个栈
stk.push(root);//根结点入栈
while(!stk.empty()){
p=stk.top();
visit(p);
stk.pop();
if(root->lchild) push(root->lchild);
if(root->rchild) push(root->rchild);
}
}
25、广度优先遍历
非递归:
(1)初始化队列Q;visited[n]=0;
(2)访问顶点v;visited[v]=1;顶点v入队列Q;
(3) while(队列Q非空)
v=队列Q的对头元素出队;
w=顶点v的第一个邻接点;
while(w存在)
如果w未访问,则访问顶点w;
visited[w]=1;
顶点w入队列Q;
w=顶点v的下一个邻接点。
26、求图G中距离顶点V的最短路径长度最大的一个顶点,设V可达其余各个顶点。
int Maxdist(AGragh *G,int v)
{
ArcNode *p;
int Qu[MAXV]; //循环队列
int front=0,rear=0; //队列的头、尾指针
int visited[MAXV]; //初始化访问数组
int i,j,k;
for(i=0;i<G->n;i++)
visited[i]=1; //初始化访问标志数组
rear++;
Qu[rear]=v; //顶点v进队
visited[v]=1; //顶点v已访问
while(front!=rear)
{
front=(front+1)%MAXV;
k=Qu[front]; //顶点k出队
p=G->adjlist[k].firstarc; //找到第一个邻节点
while(p!=NULL) //所有未访问过的相邻点进队
{
j=p->adjvex; //邻接点为顶点j
if(visited[j]==0) //若j未访问过
{
visited[j]==1;
rear=(rear+1)%MAXV; //进队
Qu[rear]=j;
}
p=p->nextarc; //找下一个邻接点
}
}
return k;
}
27、假设图G采用邻接表存储,设计一个算法判断图G中从顶点u到v是否存在简单路径。所谓简单路径是指路径上的顶点不重复。可采用深度优先遍历的方法。
// 判断G中从顶点u到V是否存在简单路径(采用深度优先的遍历算法)
bool ExistPath(ALGraph *G, int u, int v) {
ArcNode *p;
int w;
visited[u] = 1; // 置为已经访问标记
if(u == v)
return true;
p = G->adjlist[u].firstarc; // p指向顶点u的第一个相邻点
while(p != NULL) {
w = p->adjvex; // w为u的相邻顶点
if(visited[w] == 0) {
bool flag = ExistPath(G,w,v);
if(flag)
return true;
}
p = p->nextarc; // p指向u的下一个相邻点
}
}
28、假设图G采用邻接表存储,判断无向图中任意给定的两个结点是否存在一个长度为k的简单路径。
void DFS(ALGraph G, int i, int j,int k, Status on[], Status &found)
{
Static int n = 0;//记录当前路径上的顶点个数
ArcNode *p;
on[i] = TRUE;
n++;
if(i == j && n == k+1)
found = TRUE;
else
{
p = G.vertices[i].firstarc;
while(!found && p != NULL)
{
if(!on[p->adjvex])
DFS(G, p->adjvex, j, k, on ,found);
p = p->nextarc;
}
}
on[i] = FALSE;//回退操作
n--;
}
29、判别给定二叉树是否为二叉排序树的算法。
typedef struct
{
keyType key;
infoType otherinfo;
}elemtype;//结点的结构体类型
typedef struct bitreenode
{
elemtype data;
struct bitreenode *lchild,*rchild;
}bitreenode,*bitree;//二叉树的结构体类型
int storenum=0;//用于存储中序遍历时父节点的值
int flag=1;//用于判别父节点的值是否大于子节点的值
int isbstree(bitree t)/*判断是否为二叉排序树*/
{
if(t->lchild && flag)
isbstree(t->lchild);
if(t->data.key<storenum)
flag=0;//左子树一支中若父节点的值小于子节点,则flag为0
storenum=t->data.key;//更新storenum的值
if(t->rchild && flag)
isbstree(t->rchild);
return flag;
}