uiuc final 3.2

8
ECE 190 Final Exam Day Two Spring 2013 7 th May, 2013 All your answers will be submitted electronically This is a closed book exam. You may not use a calculator. You are allowed one handwritten 8.5 x 11" sheet of notes. Absolutely no interaction between students is allowed. All problems are worth 25 points but they are not equally difficult Read problem statements carefully and don’t panic! Problem number Max Score Checked by 1 25 2 25 3 25 4 25 Total 100

Upload: ace-nhat

Post on 11-Dec-2015

219 views

Category:

Documents


0 download

DESCRIPTION

Introduction to Computer Engineering

TRANSCRIPT

ECE  190  Final  Exam  Day  Two  Spring  2013  

 7th  May,  2013  

   

• All  your  answers  will  be  submitted  electronically  • This  is  a  closed  book  exam.  • You  may  not  use  a  calculator.  • You  are  allowed  one  handwritten  8.5  x  11"  sheet  of  notes.  • Absolutely  no  interaction  between  students  is  allowed.  • All  problems  are  worth  25  points  but  they  are  not  equally  difficult  • Read  problem  statements  carefully  and  don’t  panic!  

     

                                       

Problem  number  

Max   Score   Checked  by  

1   25      

2   25      

3   25      

4   25      

Total   100      

Instructions  for  accessing/working  on  the  programming  problems  • Log  into  an  EWS  Linux  machine.  

• Appendixes  A  and  D  from  the  textbook  are  provided  for  you  on  the  desktop.  

• Open  a  terminal  window.  Check  if  directory  exam3  exists.  

• Write  your  code  in  the  files  indicated  by  the  problem  statements.  Do  not  rename  the  files.  We  will  not  grade  your  problem  if  it  is  not  saved  as  required.  

• We  are  NOT  using  a  subversion  repository  for  the  exam.  We  will  grade  the  saved  files  that  you  leave  in  your  exam3  directory.  

• Your  code  will  be  at  least  partly  graded  by  an  autograder.  You  may  receive  zero  points  if  your  code  does  not  assemble,  does  not  compile,  or  does  not  behave  as  specified.  

• To  begin  work  on  problem  X,  use  the  cd  command  to  get  to  the  problemX  directory.    

• To  edit  the  file,  type  gedit  givenfilename  &    (Replace  givenfilename  with  the  name  of  the  file  where  you  will  add  your  code.)    

• Save  your  work.    

 

LC-­‐3  Tools  reference  information  • To  assemble  your  code  and  produce  the  object  file,  type  lc3as  givenfilename.asm    

• To  run  the  LC-­‐3  graphical  simulator,  type  lc3sim-­‐tk  givenfilename.obj    

• To  run  the  LC-­‐3  command-­‐line  simulator,  type  lc3sim  givenfilename.obj  

 

C  Tools  reference  information  • We  will  use  clang  compiler  when  grading  your  solutions.  

• To  compile  your  code  using  clang  compiler,  type  clang  -­‐Wall  <c  file  name>  

• To  compile  your  code  using  gcc  compiler,  type  gcc  -­‐Wall  <c  file  name>  

• To  execute  your  code,  type  ./a.out  

   

Problem  1:  Sorted  Doubly  Linked  List    Implement  a  doubly  linked  list  of  positive  integers,  which  takes  inputs  from  the  user  and  creates  a  sorted  doubly  linked  list.  In  a  sorted  doubly  linked  list,  the  head  node  will  hold  the  smallest  input  and  the  last  node  will  hold  the  largest  input.  Each  node  has  a  pointer  (next)  to  the  next  larger  node  and  a  second  pointer  (prev)  to  the  next  smaller  node.  You  are  given  the  struct  of  the  node,  and  the  console  for  the  user  within  the  main  function:    typedef  struct  node{          int  data;          struct  node*  next;          struct  node*  prev;  } NODE;   If   the  user   enters   a  positive   integer   then   the   function  addSortNode   should   add  a  node   to   the  doubly  linked   list   in   increasing  order.   In  other  words,   it  will   find  a  right   location  within  the   linked   list   to  add  a  new  node,  containing  the  input  data.  Adding duplicate values is acceptable.  If   the  user  enters  a  negative   integer  –x  then  the   function  removeNode  should   find  the   first  node  with  value  x,  provided  x  is  present  in  the  list,  and  removes  it  from  the  list  (otherwise  it  does  nothing).    If  the  user  enters  0,  the  program  prints  out  the  list  of  inputs  twice:  once  in  increasing  order  and  once  in  decreasing  order.  You  are  also  required  to  implement  the  printInc  and  printDec  functions.    For  example,  When  these  numbers  are  entered  to   the  program:  1  3  5  7  9   -­‐3   -­‐5  4  8   -­‐4  0,   the  program  should  print  out  these  two  lines  (increasing  and  decreasing  order):  1  4  7  8  9  9  8  7  4  1    

• Edit  and  save  your  work  in  problem1/main.c  file    • Do  not  change  the  main()  function.  • Do  not  modify  the  function  prototypes  for  the  four  functions  that  are  given.  • Compile:  clang  –Wall  main.c  –o  main  

   

Problem  2.  C  to  LC-­‐3  Assembly  Conversion:  Linked  List  Cycle  Detection  Convert  the  given  C  function  to  an  LC-­‐3  subroutine.  The  function  returns  1  if  the  given  linked  list  contains  a  cycle,  otherwise  it  returns  0.  An  example  of  a  linked  list  with  a  cycle  is  shown  below.  

 

 

 

The  source  code  for  the  function  is  shown  to  the  left   and   the   definition   of   the   node_t   type   is  shown  below.  

typedef  struct  node_t  {     int  data;     struct  node_t  *next;  }  node_t;    

Remember   that   structures   merely   consist   of  simple   data   types   where   one   element   always  comes   after   another   in  memory.   That   is   if  head  points   to   an  address  of   x2002,   the  data  value   is  contained  in  x2002  and  the  next  pointer  address  is  contained  within  x2003.  

 

Your   program   should   be   saved   in   the   exam3/problem2/cycle-­‐detection.asm   file.   The   file   already  contains  an  LC-­‐3  assembly  implementation  of  MAIN  that  calls  the  HAS_CYCLE  subroutine.  The  subroutine  has  code  for  saving  registers  using  the  callee-­‐save  convention.  Do  not  modify  the  MAIN  routine  or  the  code  for  saving  registers.  

data/cycle.asm  and  data/no-­‐cycle.asm  files  are  provided  for  your  convenience  for  testing.  Each  contains  a  short  hard-­‐coded  linked  list  consisting  of  7  nodes.  The  list   in  data/cycle.asm  contains  a  cycle  and  the  list   in  data/no-­‐cycle.asm  does  not   contain   a   cycle.  As   you   can   see   from  MAIN’s   implementation,   list’s  head  node  is  stored  starting  at  address  x2002.  

Your  program  should  correctly  run  in  lc3sim  (or  lc3sim-­‐tk)  and  should  produce  the  correct  output.  Your  subroutine  should  expect  the  parameter  head  to  be  passed  in  R0  and  should  place  the  return  value  in  R0.  Do  not  assume  anything  else  about  the  behavior  or  structure  of  MAIN.  

To  test  your  HAS_CYCLE  subroutine  using  the  provided  MAIN  and  the  provided  data  files,  first  assemble  cycle-­‐detection.asm,  data/cycle.asm,  and  data/no-­‐cycle.asm.  Then,   load  cycle-­‐detection.asm  and  one  of  the  data  files  in  the  lc3  simulator,  set  PC  to  x3000,  and  run  it.  

 

2   3   5   7   11   13  HEAD  

int  has_cycle(node_t  *head)  {     node_t  *tortoise;     node_t  *hare;       if  (head==NULL)  return  0;       tortoise  =  head;     hare  =  head-­‐>next;     while  (tortoise  !=NULL  &&  hare  !=  NULL          &&  hare-­‐>next  !=  NULL)  {       if  (tortoise  ==  hare)  {         return  1;       }       tortoise  =  tortoise-­‐>next;       hare  =  hare-­‐>next-­‐>next;     }       return  0;  }  

Problem  3.  Find  Triangles  in  a  Graph   In  an  undirected  graph,  a  triangle  is  formed  if  two  vertices  u  and  v,  that  are  connected  with  an  edge  (u,v),  share   a   common   neighbor   w.   That   is,   if   the   edges   (u,w)   and   (v,w)   are   also   present   in   the   graph.  Implement  a  function  countTriangles  which  returns  the  number  of  triangles  in  a  graph.  Based  on  the  above  definition,  the  following  algorithm  computes  the  number  of  triangles  in  an  undirected  graph:      

 You  are  given  code  that  reads  a  graph  from  a  file  and  fills  its  adjacency  matrix  in  a  dynamically  allocated  2D  array.  The  graph  then  resides  in  the  Graph  data  type.      typedef  struct  graph_t  Graph;  struct  graph_t  {     int  nnodes;     int  nedges;     int  **matrix;  };    For  a  pointer  to  a  graph  (Graph*)  the  elements  in  its  adjacency  matrix  are  accessed  by:    graph-­‐>matrix[i][j].      Recall,  since  the  graph  is  undirected  every  edge  is  represented  twice  in  the  adjacency  matrix  as  (u,v)  and  (v,u).  In  the  above  algorithm,  you  should  consider  each  edge  once.    

• The  main  function  in  problem3/triangles.c  reads  the  graph  from  an  input  text  file,  provides  the  user  console,  and  calls  countTriangles.  It  can  also  print  the  adjacency  matrix.  

• Write  your  implementation  of  countTriangles  in  problem3/triangles.c.    • You  may  create  functions  (e.g.,  Intersection)  that  are  called  from  inside  countTriangles.    • Do  not  change  any  of  the  given  functions.  • In  problem3/  you’ll  find  three  text  files  describing  three  graphs  (three.txt,  45.txt  and  334.txt).    • Compile:  clang  –Wall  triangles.c  –o  triangles  • Run:  ./triangles  three.txt  

   

for  each  edge  (u,v)  compute  the  size  of  the  intersection  of  the  sets  Neighbors(u)  and  Neighbors(v)  aggregate  this  size  to  a  global  sum  

The  number  of  triangles  is  the  global  sum  divided  by  3.    (Since  the  loop  above  considers  a  triangle  once  for  every  side)  

Problem  4.  Maze  solver    Given  a  maze  (a  2D  array  of  cells),  write  a  program  for  finding  a  path  from  the  source  to  the  destination  cell   using   depth-­‐first   search   (DFS).   The   maze   is   given   as   a   text   file   (see   figure   on   left).   The   first   line  declares  the  number  of  rows  and  columns.  Walls  are  represented  by  hashes  (#),  non-­‐walls  by  dots  (.),  the  source  as  S  and  the  destination  as  D.  In  problem4/maze.c  you  are  given  functions  that  read,  write,  and  print  the  maze  from  or  to  files  and  the  terminal.        

     

   

       

Maze  data  structure.  After  loading  it,  the  maze  is  represented  as  a  graph  (Figure  right)  where  each  cell  (  #,  .,  S  or  D)  is  a  vertex.  The  vertices  are  assigned  identifiers  (integers  >=  0)  row-­‐by-­‐row  as  shown  in  the  figure   above.   Edges   in   the   graph   connect   two   adjacent   non-­‐wall   vertices.   The  walls   (#)   are   therefore  vertices  without   edges.   The   graph   is   implemented   as   an   array   of   Vertex   types   as   shown   below.   Each  Vertex  has   an   id   that   corresponds   to   its   index   in   this   array   (Vertex   *nodes),   a   type   (see   pseudo-­‐code  below)  and  an  adjacency  list  of  neighbors.      

     

 

                 Maze  data  structure  representation  

5  7  #######  #S....#  #.##..#  #...#D#  #######  

   Maze  text  input  

enum  CellType  {  WALL,  UNVISITED,  VALID,  INVALID  };    typedef  struct  item_t  Item;  /*  linked  list  (for  neighbors  or  stack)  */  struct  item_t  {     int  id;     Item  *next;  };    typedef  struct  node_t  {     int  id;         /*  The  index  in  the  array  */       enum  CellType  type;   /*  Wall  or  path.  */     Item  *nbrs;       /*  Adjacent  nodes  (Neighbors)  */  }  Vertex;    typedef  struct  graph_t  {     int  rows;       /*  Number  or  rows  */     int  cols;       /*  Number  or  columns  */     int  src;       /*  Array  index  of  source  node  */     int  dst;       /*  Array  index  of  destination    node  */     Vertex  *nodes;     /*  Array  of  vertices  (nodes)  */  }  Graph;  

1   2   3   4   5   6  0  

7   8   9   10   11   12   13  

14   15   16   17   18   19   20  

21   22   23   24   25   26   27  

28   29   30   31   32   33   34  

In  maze.c  you  are  given  an  implementation  of  a  stack  with  three  functions:  push,  peek  and  pop.  Use  this  stack   to   implement   an   iterative   DFS   traversal   in   the   function   iterativeDFS   that   finds   a   path   from   the  source  to  the  destination,  along  the  lines  of  the  following  pseudo-­‐code:    

Following  the  above  pseudo-­‐code,  by  the  end  of  the  traversal  the  vertices  that  belong  to  the  path  should  be  marked  VALID,  those  that  were  visited  but  didn’t  lead  to  the  destination  should  be  marked  INVALID,  and  the  rest  should  remain  either  WALL  or  UNVISITED.   For  the  above  example  your  function  should  print  to  the  terminal:    

 For  simplicity,  the  path  is  printed  in  reverse,  from  the  destination  (here  26)  to  the  source  (here  8).  Leaving  main  function  unchanged  should  save  the  result  you  see  on  the  right  to  the  output  file  that  you  give  in  the  command  line.  In  the  end,  the  correct  path   is  composed  of  cells  with  a  plus  sign  (+),   the  visited  but  not  valid  paths  with  a  minus  sign  (-­‐)  and  the  unvisited  cells  with  a  dot  (.).      Instructions:  

• In  file  problem4/maze.c   include  your  code  in  function  iterativeDFS  without  changing  the  function’s  signature.  

function  iterativeDFS    Inputs:  graph,  source,  destination  //  At  the  start  all  vertices  are  either  WALL  or  UNVISITED  found  :=  false  ;  push  source  onto  stack  ;  mark  source  as  VALID  ;    while  stack  is  not  empty  :     u  :=  peek  the  top  of  the  stack  ;     for  each  w  in  neighbors(u)  :                                  //  Explore  potential  path       if  w  is  UNVISITED  :         mark  w  as  VALID  ;         push  w  onto  stack  ;         if  w  equals  destination  :           found  :=  true  ;  

end  if           break  ;       end  if     end  for     if  found  equals  true  :       break  ;    

end  if     if  done  with  neighbors(u)  :                                    //  Dead-­‐end.  Need  to  backtrack       v  :=  peek  the  top  of  stack  ;       mark  v  as  INVALID  ;       pop  from  stack  ;  

end  if  end  while    print  the  contents  of  the  stack  to  get  the  actual  path  ;

Path:  26  <-­‐  19  <-­‐  18  <-­‐  11  <-­‐  10  <-­‐  9  <-­‐  8  <-­‐    

5  7  #######  #++++.#  #-­‐##++#  #-­‐-­‐-­‐#+#  #######  

• Compile:  clang  –Wall  maze.c  –o  solver  • Test  your  program  input  files  (oneway.txt,  small.txt,  medium.txt)  • Run  as:  ./solver  inputfile.txt  outputfile.txt  • The  outputfile.txt  will  be  overwritten  and  should  contain  the  maze  traversal.  • Indicative  results  (though  any  valid  path  from  the  source  to  destination  is  correct):  

 oneway.txt:    

small.txt:    

medium.txt:    

   

   

 

Path:  26  <-­‐  19  <-­‐  12  <-­‐  11  <-­‐  10  <-­‐  17  <-­‐  24  <-­‐  23  <-­‐  22  <-­‐  15  <-­‐  8  <-­‐  

Path:  26  <-­‐  19  <-­‐  18  <-­‐  11  <-­‐  10  <-­‐  9  <-­‐  8  <-­‐  

Path:  60  <-­‐  71  <-­‐  70  <-­‐  69  <-­‐  58  <-­‐  47  <-­‐  46  <-­‐  45  <-­‐  34  <-­‐  23  <-­‐  12  <-­‐