uiuc final 3.3

Upload: ace-nhat

Post on 09-Jan-2016

215 views

Category:

Documents


0 download

DESCRIPTION

Electrical & Electronic Engineering, Introduction to Computer Engineering

TRANSCRIPT

  • ECE 190 Final Exam Day Three Spring 2013

    8th 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 dont 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

    To compile your code using gcc compiler, type gcc -Wall

    To execute your code, type ./a.out

  • Problem 1. Detect common node. Implement a C function detect () in the file problem1/detect.c which detects the first common node in two singly linked lists. The function prototype and the node struct are as follows: node* detect (node* A, node* B); typedef struct node { int val; struct node *next; } The node* next is the link to the next node in the linked list. The detect function will be called with two arguments node* A, node* B. A and B point to heads of two linked lists which share common nodes. In the example below, the first common node is node with value 1. The function should return the address of the first common node. The function should return NULL when A or B is NULL or no common node is found.

    Here is a pseudo-code that you may follow:.

    Traverse linked list A one node at a time o For each node of A, traverse linked list B one node at a time

    If the node in A and in B we are checking are the same node, return this same nodes address and exit your function.

    If no common node is found return NULL.

    l We will test corner cases when the return value should be NULL l Edit and save your function in problem1/detect.c l Leave other files unchanged. l Compile: clang Wall g detect.c main.c o problem1

  • C to LC-3 Assembly Conversion: Linked List Pairwise Rotation Convert the given C function to an LC-3 subroutine. The function swaps pairs of elements in a linked list. An example of the function's operation is given below.

    Input:

    Output:

    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 x2000, the data value is contained in x2000 and the next pointer address is contained within x2001.

    Your program should be saved in the exam3/problem2/pairwise-rotation.asm file. The file already contains an LC-3 assembly implementation of MAIN that

    calls the PAIRWISE_ROTATE subroutine. You should not modify the MAIN routine.

    data.asm file is provided for convenient testing. It has a hard-coded linked list of 6 nodes. As you can see from MAINs implementation, lists head is stored starting at address x2000.

    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. Your subroutine should save and restore the registers using the callee-save convention. Do not make any assumptions about the behavior or structure of MAIN beyond the parameter passing explained above.

    To test your PAIRWISE_ROTATE subroutine using the provided MAIN and data.asm, assemble both pairwise-rotation.asm and data.asm, load them in the lc3 simulator, set PC to x3000, and run it. You can inspect the list at x2000 and the head pointer at label HEAD to see if the correct changes are made.

    1 2 3 4 5 6 NULL HEAD

    2 1 4 3 6 5 NULL HEAD

    int pairwise_rotate(node_t **head){ node_t *p, *q, *tmp; if (head == NULL || *head == NULL || (*head)->next == NULL) { return 1;} p = *head; q = (*head)->next; *head = q; tmp = q->next; q->next = p; p->next = tmp; while (tmp!=NULL && tmp->next!=NULL) { q = tmp->next; p->next = q; p = tmp; tmp = q->next; q->next = p; q->next = tmp; } return 0; }

  • Problem 3. Lowest Common Ancestor in a Binary Search Tree The Lowest Common Ancestor (LCA) of two nodes v1 and v2 in a Binary Search Tree (BST) T is a unique node x in T such that (a) both v1 and v2 are in the subtree starting from x, and (b) this subtree of x is the smallest subtree in T that contains v1 and v2. The LCA of 4 and 14 in the example below is 8.

    Write a C function which takes as input (a) the values v1 and v2 of two nodes in a BST, and (b) a pointer to the root of the BST, and computes the LCA of the corresponding nodes. Assume both v1 and v2 are present in the tree, v1 < v2, and that all the values in T are unique. The function prototype and the node struct are as follows: int FindLCA(node* root, int v1, int v2); struct node { int data; struct node* left; struct node* right; };

    Algorithm: 1. Start LCA search with current_node = root. 2. If value of current_node is between v1 and v2 (including v1 and v2) then it is the LCA. 3. Otherwise if current_node's value is greater than both v1 and v2 then recursively continue LCA

    search with left child of current_node. 4. Else, current_node's value is less than both v1 and v2 and in this case recursively continue LCA

    search with right child of current_node. In the problem3/ LCA.c file the main() function builds a BST and calls FindLCA.

    Implement the function FindLCA function in this file. Do not change anything else. Of course, your implementation should work for any BST. Compile: clang Wall g LCA.c o LCA

  • Problem 4. Shortest path with possibly negative edge weights For this question you will be implementing the Bellman-Ford algorithm to find the shortest path to all nodes from a single source in a graph. Bellman-Ford is similar to Dijkstra's algorithm you implemented for MP5 but it works even with negative edge weights. If a cycle of negative weight exists, however, there is no shortest path and Bellman-Ford detects it. Relaxing an edge (u,v) consists of testing whether we can improve the shortest path from source to v found so far by going through u and, if so, updating the distance to v from the source and its predecessor. This is equivalent to the following pseudocode, where dist[x] is the distance to vertex x from source, weight[u,v] is the weight of the edge between u,v, and predeessor[x] is the predecessor of x along the shortest path from source to x. : if dist[u] + weight(u,v) < dist[v]: dist[v] = dist[u] + weight(u,v) predecessor[v] = u ; end if In Bellman-Ford you have to loop through all edges and relax them |V(G)|-1 times, where |V(G)| is the number of vertices in the graph. The complete pseudo-code for Bellman-Ford is listed below: // Step1: Initialize for each vertex v in vertices: if v is source dist[v] := 0 ; else dist[v] := infinity ; end if predecessor[v] := null ; end for // Step 2: relax edges repeatedly for i from 1 to size(vertices)-1: for each edge(u, v) with weight w(u,v) in edges: if dist[u] + w(u,v) < dist[v]: dist[v] := dist[u] + w(u,v) ; predecessor[v] := u ; end if end for end for // Step 3: Detect negative cycles for each edge(u, v) with weight w(u,v) in edges: if dist[u] + w < dist[v]: error "Graph contains a negative-weight cycle" end if end for

  • Implementation Instructions To implement the Bellman-Ford algorithm, you will be using the same representation (structs) as

    in MP5. The functions addNode, addEdge, readNodeFile, readEdgeFile are given to you so that you can

    build the graph and run your algorithm. Your implementation should be placed in the file problem4/main.c inside the function with

    signature: int bellmanFord (char* source, float *distance, int *predecessors) If a negative cycle is detected, this function should return -1 otherwise should return 1. To compile use clang -Wall g main.c graph.c To run ./a.out