Lead: Roth (UIUC) Abdelzaher (UIUC) Huang (UIUC) Lei (IBM) Presented by: Tarek Abdelzaher.
UIUC Final 3.2
description
Transcript of UIUC Final 3.2
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 <-‐