山東科技大學_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的正整數,每個使用者i
(i
=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(log2n)
x2-15:
這個一看就知道D是頂點集,R是邊集,所以肯定是圖
x2-16:
這個就是考拓撲序的定義,不知道啥是拓撲序的百度就好
x2-17:
這個就是A,可別錯選成C
x2-18:
二分查詢次數不超過【log2n】+1(以2為底n的對數)