山东科技大学_2018数据结构期末考试_(A卷)带详解

版权声明:欢迎转载,但转载时请注明原文地址 https://blog.csdn.net/weixin_42110638/article/details/85233701

17级计科与信安的数据结构期末题(A卷)

这个判断选择的顺序考试时都是打乱的,我这个是作废版的,顺序有点混乱,但题都是一样的

解析在后面!!!

有不会的私聊我就好

一.判断题

二.选择题

三.函数题

6-1 先序输出叶结点 (12 分)

本题要求按照先序遍历的顺序输出给定二叉树的叶结点。

函数接口定义:

void PreorderPrintLeaves( BinTree BT );

其中BinTree结构定义如下:

typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
    ElementType Data;
    BinTree Left;
    BinTree Right;
};

函数PreorderPrintLeaves应按照先序遍历的顺序输出给定二叉树BT的叶结点,格式为一个空格跟着一个字符。

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>

typedef char ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
    ElementType Data;
    BinTree Left;
    BinTree Right;
};

BinTree CreatBinTree(); /* 实现细节忽略 */
void PreorderPrintLeaves( BinTree BT );

int main()
{
    BinTree BT = CreatBinTree();
    printf("Leaf nodes are:");
    PreorderPrintLeaves(BT);
    printf("\n");

    return 0;
}
/* 你的代码将被嵌在这里 */

输出样例(对于图中给出的树):

Leaf nodes are: D E H I

答案:

啥难度都没有

递归先序遍历输出结点时判断下,是空的就输出即可

void PreorderPrintLeaves( BinTree BT )
{
    if(BT)
    {
        if(!BT->Left&&!BT->Right)
            printf(" %c",BT->Data);
        PreorderPrintLeaves(BT->Left);
        PreorderPrintLeaves(BT->Right);
    }
    return;
}

6-2 带头结点的单链表就地逆置 (13 分)

本题要求编写函数实现带头结点的单链线性表的就地逆置操作函数。L是一个带头结点的单链表,函数ListReverse_L(LinkList &L)要求在不新开辟节点的前提下将单链表中的元素进行逆置,如原单链表元素依次为1,2,3,4,则逆置后为4,3,2,1。

函数接口定义:

void ListReverse_L(LinkList &L);

其中 L 是一个带头结点的单链表。

裁判测试程序样例:

//库函数头文件包含
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>

//函数状态码定义
#define TRUE        1
#define FALSE       0
#define OK          1
#define ERROR       0
#define INFEASIBLE -1
#define OVERFLOW   -2

typedef int  Status;
typedef int  ElemType; //假设线性表中的元素均为整型

typedef struct LNode
{
    ElemType data;
    struct LNode *next;
}LNode,*LinkList;

Status ListCreate_L(LinkList &L,int n)
{
    LNode *rearPtr,*curPtr;   //一个尾指针,一个指向新节点的指针
    L=(LNode*)malloc(sizeof (LNode));
    if(!L)exit(OVERFLOW);
    L->next=NULL;               //先建立一个带头结点的单链表
    rearPtr=L;  //初始时头结点为尾节点,rearPtr指向尾巴节点
    for (int i=1;i<=n;i++){  //每次循环都开辟一个新节点,并把新节点拼到尾节点后
        curPtr=(LNode*)malloc(sizeof(LNode));//生成新结点
        if(!curPtr)exit(OVERFLOW);
        scanf("%d",&curPtr->data);//输入元素值
        curPtr->next=NULL;  //最后一个节点的next赋空
        rearPtr->next=curPtr;
        rearPtr=curPtr;
    }
    return OK;
}
void ListReverse_L(LinkList &L);
void ListPrint_L(LinkList &L){
//输出单链表
    LNode *p=L->next;  //p指向第一个元素结点
    while(p!=NULL)
    {
          if(p->next!=NULL)
               printf("%d ",p->data);
          else
               printf("%d",p->data);
          p=p->next;
    }
}
int main()
{
    LinkList L;
    int n;
    scanf("%d",&n);
    if(ListCreate_L(L,n)!= OK) {
          printf("表创建失败!!!\n");
          return -1;
    }
    ListReverse_L(L);
    ListPrint_L(L);
    return 0;
}
/* 请在这里填写答案 */

输入格式

第一行输入一个整数n,表示单链表中元素个数,接下来一行共n个整数,中间用空格隔开。

输出格式

输出逆置后顺序表的各个元素,两个元素之间用空格隔开,最后一个元素后面没有空格。

输入样例:

4
1 2 3 4

输出样例:

4 3 2 1

答案:

这个还是有难度的

思路:逆置链表初始为空,表中节点从原链表中依次“删除”,再逐个插入逆置链表的表头(即“头插”到逆置链表中),使它成为逆置链表的“新”的第一个结点,如此循环,直至原链表为空。

借鉴一位大佬的图:

void ListReverse_L(LinkList &L)//L为头结点
{
    LinkList p,q;
    p = L->next;
    L->next = NULL;
    while(p)
    {
        //向后挪
        q = p;//
        p = p->next;
        //头插
        q->next = L->next;//非常重要,相当于p和q之间没有了指针连接
        L->next = q;//把q接到头的后面
    }
}
 
 

7-1 悄悄关注 (10 分)

新浪微博上有个“悄悄关注”,一个用户悄悄关注的人,不出现在这个用户的关注列表上,但系统会推送其悄悄关注的人发表的微博给该用户。现在我们来做一回网络侦探,根据某人的关注列表和其对其他用户的点赞情况,扒出有可能被其悄悄关注的人。

输入格式:

输入首先在第一行给出某用户的关注列表,格式如下:

人数N 用户1 用户2 …… 用户N

其中N是不超过5000的正整数,每个用户ii=1, ..., N)是被其关注的用户的ID,是长度为4位的由数字和英文字母组成的字符串,各项间以空格分隔。

之后给出该用户点赞的信息:首先给出一个不超过10000的正整数M,随后M行,每行给出一个被其点赞的用户ID和对该用户的点赞次数(不超过1000),以空格分隔。注意:用户ID是一个用户的唯一身份标识。题目保证在关注列表中没有重复用户,在点赞信息中也没有重复用户。

输出格式:

我们认为被该用户点赞次数大于其点赞平均数、且不在其关注列表上的人,很可能是其悄悄关注的人。根据这个假设,请你按用户ID字母序的升序输出可能是其悄悄关注的人,每行1个ID。如果其实并没有这样的人,则输出“Bing Mei You”。

输入样例1:

10 GAO3 Magi Zha1 Sen1 Quan FaMK LSum Eins FatM LLao
8
Magi 50
Pota 30
LLao 3
Ammy 48
Dave 15
GAO3 31
Zoro 1
Cath 60

输出样例1:

Ammy
Cath
Pota

输入样例2:

11 GAO3 Magi Zha1 Sen1 Quan FaMK LSum Eins FatM LLao Pota
7
Magi 50
Pota 30
LLao 48
Ammy 3
Dave 15
GAO3 31
Zoro 29

输出样例2:

Bing Mei You

答案:

这个题我是用Java写的,有一个样例会超时。。。

大体的思路就是一个arraylist两个map(一个map一个map2),如果map的key不在list中,就把这个map对应的key和value存到map2中,再对map2进行排序即可

不过这个题时间卡的很紧,STL或者java的容器都会超时。

这个题考试时,超时的话十分给8分,不会的话直接输出也能得三分。。。

还有个问题,就是关于输入,我这个题考试就得了3分。。。就是因为STL的map不会使,java不会输入。。。

记住java的String输入,next()是遇到空格就截止,nextline()是遇到换行才截止,不然就一直读。。。

现在想想真心累。。。

import java.util.*;

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc = new Scanner(System.in);
		List<String> list = new ArrayList<String>();
		//请注意这个输入!!!nextLine是一直输入,遇到换行才停止。next则是遇到空格就停止
		int n = sc.nextInt();
		//sc.next();
		String s1 = sc.nextLine();
		String []s2 = s1.split(" ");
		int m = sc.nextInt();
		sc.nextLine();
		Map<String,Integer> map = new HashMap<String,Integer>();
		for(int i = 0;i < m;i++)
		{
			String a = sc.next();
			int b = sc.nextInt();
			map.put(a, b);
		}
		for(int i = 0;i < s2.length;i++)
		{
			list.add(s2[i]);
		}
	    //System.out.println(0);
	   // System.out.println(map);
		int average = 0,sum = 0;
		for(Integer i : map.values())
		{
			sum += i;
		}
		average = sum/m;//求出average
		//System.out.println(average+" "+sum);
		
		Map<String,Integer> map2 = new HashMap<String,Integer>();
		//遍历map,如果map的key不包含在list中,就把那个map的key和value放到map2中
		for (Map.Entry<String, Integer> entry : map.entrySet())
		{
				if(!list.contains(entry.getKey())&&entry.getValue()>average)
				{
					map2.put(entry.getKey(), entry.getValue());
				}
		}
		//System.out.println(map2);
		if(map2.isEmpty())
		{
			System.out.println("Bing Mei You");
		}
		else
		{
			//System.out.println("hh");
			List<Map.Entry<String, Integer>> lis = new ArrayList<Map.Entry<String, Integer>>(map2.entrySet());
	        Collections.sort(lis, new Comparator<Map.Entry<String, Integer>>() {
			public int compare(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) {
				return e1.getKey().compareTo(e2.getKey());
			}
			});
	        for(int i = 0;i < lis.size();i++)
	        {
	        	System.out.println(lis.get(i).getKey());
	        }
	    }
	    
	    
    }
}
		
		
	
		
		
		
		

这是一个大佬写的Accept代码

#include<stdio.h>
#include<string>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
using namespace std;
int main()
{
	int n,m,i,j,k=0,s=0,f=0,a,fag=0;
	string s1,s2;
	map<string,int>p;
	set<string>p1;
	cin>>n;
	for(i=0;i<n;i++)
	{
		cin>>s1;
		p[s1]=0;
	}
	cin>>m;
	int c[m];
	char b[m][10];
	for(i=0;i<m;i++)
	{
		cin>>s2>>a;
		s=s+a;
		if(p.find(s2)==p.end())
		{
		     for(j=0;j<sizeof(s2);j++)
		     {
		     	b[k][j]=s2[j];
			 }
			 c[k]=a;
			 k++;
		}
		else
		{
			p[s2]=a;
		}
	}
	s=s/m;
	for(i=0;i<k;i++)
	{
		if(c[i]>s)
		{
		    p1.insert(b[i]);
		    f++;
			fag=1;
		}
	}
	if(fag==0)
	{
		printf("Bing Mei You");
	}
	else
	{
		set<string>::iterator it;
		for(it=p1.begin();it!=p1.end();it++)
		{
			cout<<*it<<endl;
		}
	}
	return 0;
}

解析:

p1-1:

后者把2提到前面,N方肯定比2N快

p1-2:

访问结点必须要找到他的直接前驱,需要遍历单链表,时间复杂度O(N)

p1-3:

他是循环(环状)队列,rear可能会等于0的

p1-4:

4输出完了之后不是5的话不可能直接输出1

p1-5:

顺序表一定连续,链表很随性,连不连续都成

p1-6:

堆的每个同一层之间并没有顺序,这题不会的话好好理解堆的定义去

p1-7:

画一画就知道不可能

p1-8:

p1-10:

只要理解了啥是平方探测法(当然要注意这道题的平方探测不太正规,没有负的,那其实就更简单了)

这个题没任何难度

p1-11:

prime算法就是让一颗小树长大的过程

x2-2:

逻辑上可以把数据结构分成:线性结构和非线性结构

x2-3:

链栈的top指针应该设在头部

x2-4:

这个没啥可说的

x2-5:

画图就好了

x2-6:

x2-7:

这个其实你只要会了森林转换成二叉树的方法画个图自己看看就成

比如最下面这个图,你看看bd和ac的过程就会发现只有父子和兄弟两种关系

无法成为u的父亲与v的父亲是兄弟的尴尬关系。hhhh

x2-8:

x2-9:

具有n个顶点的有向完全图有n*(n-1)条弧,即完全无向图的2倍

x2-11:

三趟每次都是最大的在最后边,所以是冒泡

x2-12:

快排最好的时候为O(NlogN),最坏时是O(N)方

x2-13:

二分查找的时间复杂度:O(log​2​​n)
x2-15:

这个一看就知道D是顶点集,R是边集,所以肯定是图

x2-16:

这个就是考拓扑序的定义,不知道啥是拓扑序的百度就好

x2-17:

这个就是A,可别错选成C

x2-18:

二分查找次数不超过【log2n】+1(以2为底n的对数)

猜你喜欢

转载自blog.csdn.net/weixin_42110638/article/details/85233701