整理了数据结构课程期末常考的选填题,用C实现求解,方便考试快速解答~
一、二叉树的恢复
前+中->后
已知树的前序遍历和中序遍历序列,输出后序遍历序列。
例题:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
struct TreeNode{
int val;
struct TreeNode *left,*right;
};
//接收一个子根,创造左右子树
void createTree(struct TreeNode **T,int *preOrder,int preStart,int preEnd,int *inOrder,int inStart,int inEnd)
{
if(inStart>inEnd)
return ;
(*T)=(struct TreeNode *)malloc(sizeof(struct TreeNode));
(*T)->val=preOrder[preStart];
(*T)->left=(*T)->right=NULL;
if(preStart==preEnd)
return ;
int headVal=preOrder[preStart];
int index=0;
while(inOrder[index]!=headVal) //index指向子根
index++;
int n=index-inStart;
createTree(&(*T)->left,preOrder,preStart+1,preStart+n,inOrder,inStart,index-1);
createTree(&(*T)->right,preOrder,preStart+n+1,preEnd,inOrder,index+1,inEnd);
}
struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize)
{
struct TreeNode *root=NULL;
createTree(&root,preorder,0, preorderSize-1,inorder,0,inorderSize-1);
return root;
}
void postTravel(struct TreeNode *root)
{
if(root)
{
postTravel(root->left);
postTravel(root->right);
printf("%d ",root->val);
}
}
int main(int argc, const char * argv[]) {
int pre[100],in[100];
int preSize,inSize;
scanf("%d%d",&preSize,&inSize); //先输入数组元素个数
int i;
for(i=0;i<preSize;i++)
scanf("%d",&pre[i]); //再输入前序序列
for(i=0;i<inSize;i++)
scanf("%d",&in[i]); //再输入中序序列
struct TreeNode *root=buildTree(pre,preSize,in,inSize);
postTravel(root); //输出后序遍历结果
return 0;
}
中+后->前
例题:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
struct TreeNode{
int val;
struct TreeNode *left,*right;
};
struct TreeNode *travelTree(int *inorder, int inBegin, int inEnd, int *postorder, int postBegin, int postEnd){
if(postBegin>postEnd)
return NULL; //没有元素
struct TreeNode *root=(struct TreeNode *)malloc(sizeof(struct TreeNode));
root->val=postorder[postEnd];
root->left=NULL;
root->right=NULL;
if(postBegin==postEnd)
return root; //只有一个元素,就是根节点
int inRoot;
for(inRoot=inBegin;inorder[inRoot]!=postorder[postEnd];inRoot++)
;
root->left=travelTree(inorder,inBegin,inRoot-1,postorder,postBegin,postBegin+inRoot-inBegin-1);
root->right=travelTree(inorder,inRoot+1,inEnd,postorder,postBegin+inRoot-inBegin,postEnd-1);
return root;
}
struct TreeNode* buildTree2(int* inorder, int inorderSize, int* postorder, int postorderSize){
struct TreeNode *root=NULL;
if(inorderSize)
root=travelTree(inorder,0,inorderSize-1,postorder,0,postorderSize-1);
return root;
}
void preTravel(struct TreeNode *root)
{
if(root)
{
printf("%d ",root->val);
preTravel(root->left);
preTravel(root->right);
}
}
int main(int argc, const char * argv[]) {
int in[100],post[100];
int inSize,postSize;
scanf("%d%d",&inSize,&postSize); //先输入数组元素个数
int i;
for(i=0;i<inSize;i++)
scanf("%d",&in[i]); //再输入中序序列
for(i=0;i<postSize;i++)
scanf("%d",&post[i]); //再输入后序序列
struct TreeNode *root=buildTree2(in,inSize,post,postSize);
preTravel(root); //输出前序遍历结果
return 0;
}
二、堆排序
下标从1起,输入一组数据,输出构成的大顶堆并排序。
例题:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
void adjust(int a[],int i,int n) //调整堆,i要调整的堆(可以是一小部分)的root下标
{
int j,temp;
temp=a[i];
j=2*i; //j是i的左孩子
while(j<=n)
{
if(j<n && a[j]<a[j+1]) //j是较大的那个子结点
j++;
if(temp>=a[j]) //已满足堆
break;
a[j/2]=a[j]; //父亲比孩子小,需要交换
j=2*j;
}
a[j/2]=temp;
}
void heapSort(int a[],int n)
{
int i,temp;
for(i=n/2;i>=1;i--) //初始化堆
adjust(a,i,n);
for(i=1;i<=n;i++)
printf("%d ",a[i]); //输出大顶堆
for(i=n-1;i>=1;i--)
{
temp=a[i+1];
a[i+1]=a[1]; //最大元素放队尾
a[1]=temp;
adjust(a,1,i);
}
}
int main(int argc, const char * argv[]) {
int dui[100];
int n;
scanf("%d",&n); //先输入元素个数
for(int i=1;i<=n;i++)
{
scanf("%d",&dui[i]); //逐个输入
}
heapSort(dui,n); //实现堆排序,过程中可以输出首次成的大顶堆//
return 0;
}
三、出栈合理性判断
给出入栈出栈序列,判断出栈顺序是否合理,如果合理,求栈需要开多大。
例题:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int in[105]; //入栈序列
int out[105]; //出栈序列
int stack3[105];
int top3=-1;
int main(int argc, const char * argv[]) {
int n;
scanf("%d",&n); //输入元素个数
int i,j,cnt=0;
for(i=0;i<n;i++)
scanf("%d",&in[i]); //输入入栈元素,保证各不相同
for(j=0;j<n;j++)
scanf("%d",&out[j]);//输入出栈元素,保证各不相同
j=0;
for(i=0;i<n;i++)
{
stack3[++top3]=in[i]; //当前元素进栈
if(top3+1>cnt)
cnt=top3+1; //更新cnt
while(top3>=0 && out[j]==stack3[top3])
{
printf("%d ",stack3[top3]); //输出实际出栈序列
j++;
top3--;
}
}
if(top3==-1)
printf("\n%d",cnt); //输出最大栈容量
else
printf("\n不合法"); //没有全部出栈,不合法
return 0;
}
四、Josephus问题
n个人,从编号为k的人开始报数,数到m的人出列,他的下一个人从1开始报数,直到全部出列。输出淘汰序列。
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
typedef struct jnode{
int num;
struct jnode *next;
}*NodePtr;
void JosephusNode(int n,int m,int k) //n个人,从编号为k的人开始报数,数到m的人出列
{
NodePtr list=NULL,p=NULL,r=NULL;
int i;
for(i=1;i<=n;i++)
{
p=(NodePtr)malloc(sizeof(struct jnode));
p->num=i;
if(list==NULL)
list=p;
else
r->next=p;
r=p;
}
p->next=list;
p=list; //建立一个循环链表
for(i=1;i<k;i++) //p指向第一个出发结点
{
r=p;
p=p->next;
}
while(p->next!=p) //跳出循环时只剩一个结点
{
for(i=1;i<m;i++) //该把p指的删掉
{
r=p;
p=p->next;
}
r->next=p->next;
printf("%4d",p->num); //输出被删掉的结点号
free(p);
p=r->next;
}
printf("\nlast out: %4d\n",p->num);
}
int main(int argc, const char * argv[]) {
int n,m;
scanf("%d%d",&n,&m); //输入
JosephusNode(n,m,1); //过程中输出淘汰成员
return 0;
}
五、哈夫曼树
以一组权值构建哈夫曼树,求带权路径和。
例题:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
struct hnode{ //树结点
int val; //自身值,也即权值
struct hnode *lchild,*rchild;
struct hnode *next; //按频率(由小到大)排的链表
};
struct hnode *hroot; //哈夫曼树根
struct hnode *hhead; //head指向头节点,便于建树
int hcnt;
struct hnode *createHNode(int val)
{
struct hnode *p=(struct hnode *)malloc(sizeof(struct hnode));
p->val=val;
p->lchild=p->rchild=p->next=NULL;
return p;
}
void insertHLink(struct hnode *p)
{
struct hnode *q;
for(q=hhead;q->next && p->val>=q->next->val;q=q->next)
;
p->next=q->next;
q->next=p;
}
void hdfs(struct hnode *r,int step) //当前在第step层,root为第1层
{
if(r==NULL)
return ;
if(r->lchild==NULL && r->rchild==NULL)
{
hcnt+=(step-1)*r->val;
}
hdfs(r->lchild,step+1);
hdfs(r->rchild,step+1);
}
int main(int argc, const char * argv[]) {
int n;
scanf("%d",&n); //输入数据数
int i,tmp;
hhead=createHNode(824);
for(i=0;i<n;i++)
{
scanf("%d",&tmp); //依次输入数据
struct hnode *p=createHNode(tmp);
insertHLink(p);
}
while(hhead->next->next)
{
struct hnode *q1,*q2,*qq;
q1=hhead->next;
q2=hhead->next->next;
qq=createHNode(q1->val+q2->val);
qq->lchild=q1;
qq->rchild=q2;
hhead->next=q2->next;
insertHLink(qq);
}
hroot=hhead->next;
hdfs(hroot,1);
printf("%d",hcnt); //打印带权路径总和
return 0;
}
六、队列个数
例题:
#include <stdio.h>
int main(int argc,const char *argv[]){
int n;
scanf("%d",&n); //输入数据总数
int in[105],out[105]; //out[i]是第i个出队元素对应的进队下标0~n-1
//进队序列是:e1,e2,e3,e4,e5,e6,e7,e8,e9
int i,j,k,w,temp;
for(i=1;i<=n;i++)
scanf("%d",&in[i]); //输入入队序列
for(i=1;i<=n;i++) //出队序列是e8,e4,e2,e5,e3,e9,e1,e6,e7
{
scanf("%d",&temp); //输入出队序列
for(j=1;j<=n;j++)
{
if(temp==in[j])
{
out[i]=j;
break;
}
}
}
int queue[25][25];
int qtop=-1;
for(i=0;i<25;i++)
{
for(j=0;j<25;j++)
queue[i][j]=0;
}
queue[++qtop][0]=out[1];
for(i=2;i<=n;i++)
{
k=-1;
for(j=0;j<=qtop;j++)
{
w=0;
while(queue[j][w+1])
w++;
if(out[i]>queue[j][w])
{
if(k==-1 || queue[j][0]>queue[k][0]) //更优,更新k
k=j;
}
}
if(k==-1) //需要新建队
queue[++qtop][0]=out[i];
else //入已存在的队
{
j=1;
while(queue[k][j]!=0) //一定是插在队尾
j++;
queue[k][j]=out[i];
}
}
for(i=0;i<=qtop;i++)
{
j=0;
while(queue[i][j]!=0)
{
printf("%d ",queue[i][j]); //把输出序列按队输出
j++;
}
puts("");
}
return 0;
}
-
测试样例
输入:
9 1 2 3 4 5 6 7 8 9 8 4 2 6 3 9 1 5 7
输出:
8 9 4 6 7 2 3 5 1