1. 程式人生 > >山東科技大學_2018資料結構期末考試_(A卷)帶詳解

山東科技大學_2018資料結構期末考試_(A卷)帶詳解

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的對數)