Question
The Assignment Your goal for this assignment is to create a tool that manages an equivalence relation that can be changed in a specific way
The Assignment
Your goal for this assignment is to create a tool that manages an equivalence relation that can be changed in a specific way by the program while the program runs. The assignment will involve creating two files, equiv.h and equiv.cpp.
For this assignment, the equivalence relation is always over a set of integers {1, 2, 3, , n} for some positive integer n.
This tool is not a complete program. It is intended to be part of a larger program. File equiv.cpp must not contain a 'main' function.
Equiv.h will contain function prototypes, but it must not contain any full function definitions. (There must be no function bodies.) Equiv.cpp must contain line
#include "equiv.h"
before any function definitions.
Interface
The interface tells exactly what this module provides for other modules to use. Other modules must not use anything that is not described here. Briefly, the interface includes a type, ER, which is the type of an equivalence relation, and the following functions.
ER newER(const int n); void destroyER(ER R); bool equivalent(ER R, const int x, const int y); void merge(ER R, const int x, const int y);
Additionally, there is one function that is solely for debugging.
void showER(const ER R, const int n);
There is one more function that is part of the implementation but not part of the interface. You can use it for debugging, though.
int leader(ER R, const int x);
A module that uses this tool can create an equivalence relation called R by saying
ER R = newER(n);
where n is a positive integer. Initially, each number is in its own equivalence class; the equivalence classes are {1}, {2}, , {n}. There are two operations that can be performed.
-
equivalent(R, x, y) returns a boolean value: true if x and y are currently in the same equivalence class in equivalence relation R, and false otherwise.
-
merge(R, x, y) modifies equivalence relation R by making x and y equivalent. It combines the equivalence class that contains x with the equivalence class that contains y. The merge function does not return an answer.
Example
For example, suppose that n = 7. The following shows a sequence of operations and shows the equivalence classes after each merge operation.
Step | Result |
---|---|
ER R = newER(7) | R = {1} {2} {3} {4} {5} {6} {7} |
merge(R, 1, 5) | R = {1, 5} {2} {3} {4} {6} {7} |
merge(R, 2, 7) | R = {1, 5} {2, 7} {3} {4} {6} |
equivalent(R, 1, 5) | yields true |
equivalent(R, 1, 7) | yields false |
merge(R, 5, 7) | R = {1, 2, 5, 7} {3} {4} {6} |
equivalent(R, 2, 5) | yields true |
equivalent(R, 2, 3) yields false | yields false |
merge(R, 2, 3) | R = {1, 2, 3, 5, 7} {4} {6} |
equivalent(R, 3, 7) | yields true |
equivalent(R, 4, 7) | yields false |
merge(R, 4, 6) | R = {1, 2, 3, 5, 7} {4, 6} |
merge(R, 2, 3) | R = {1, 2, 3, 5, 7} {4, 6} |
As you can see from the last step, it is allowed to merge two values that are already equivalent. That should cause no change.
An Algorithm for Managing an Equivalence Relation
You will not store the equivalence classes directly. Instead, you will store them implicitly, using the following ideas. You are required to implement an equivalence manager in this way. You will receive no credit for a module that does not follow this algorithm.
-
Each equivalence class has a leader, which is one of the members of that equivalence class. You will create a function leader(R, x) that returns the current leader of the equivalence class that contains x in equivalence relation R.
Two values are equivalent if they have the same leader.
-
There is another idea that is similar to a leader, but not exactly the same. Each value has a boss, which is a value in its equivalence class. For the purposes of describing the idea, let's write boss[x] for x's boss.
-
If x is the leader of its equivalence class then boss[x] = 0, indicating that x has no boss.
-
If x is not the leader of its equivalence class then boss[x] 0 and boss[x] is closer to the leader, in the following sense. If you look at the values x, boss[x], boss[boss[x]], boss[boss[boss[x]]], then you will eventually encounter x's leader (just before you encounter 0).
-
Details on the algorithm
Use an array to store the bosses. Declaration
typedef int* ER;
defines type ER to be the same as int*. Write the following functions.
-
newER(n) returns an equivalence relation as an array of n+1 integers. Allocate the array in the heap. This array will be used to store the bosses. If R has type ER then R[x] is x's boss.
In C++, arrays start at index 0. You will use indices 1, n, so you need to allocate n+1 slots. (Index 0 will not be used.)
Initialize the array so that each value is a leader of its own equivalence class. That is, R[x] = 0 for x = 1, , n.
-
leader(R, x) returns the leader of x in equivalence relation R. To compute x's leader, just follow the bosses up to the leader. Here is a sketch of a loop that finds the leader of x.
y = x while(boss[y] != 0) y = boss[y] return y
You can use a loop or recursion the leader function. Any function that wants to compute a leader must use the leader function to do that. -
equivalent(R, x, y) returns true if x and y have the same leader in R. Notice that is not the same as saying that they have the same boss.
-
merge(R, x, y) merges the equivalence classes of x and y in R as follows. First, it finds the leaders x and y of x and y. If x and y are different (so x and y are not already in the same equivalence class) then y becomes the new boss of x and y becomes the leader of the combined equivalence class.
-
destroyER(R) deallocates R.
-
showER(R, n) prints the entire contents of array R (of size n) in a readable form for debugging. Be sure that showER shows both k and k's boss, for each k.
Do not try to be too fancy here. Do not try to show the equivalence classes. ShowER is a debugging tool, and it should show the bosses.
Important Note. |
---|
It is crucial for your merge function never to change the boss of a nonleader. If you are not sure that x is a leader, do not change R[x]. Pay attention to this! In the past, many students have ignored this requirement. Needless to say, their modules did not work and their scores were low. |
Additional Requirements
It is important for you to follow the algorithms and design described here. Do not make up your own algorithm. Implement exactly the functions that are indicated. Keep the parameter order as shown here. If you change the parameter order, your module will not compile correctly with my tester. Do not add extra responsibilities to functions.
The definition of ER must only be in equiv.h. Do not duplicate that definition in equiv.cpp.
A Refinement Plan
Development plan | |
---|---|
1. Create a directory (folder) to hold assignment 4. Put all of the files for this assignment in that directory. Start by getting files Makefile, dotest and testequiv.cpp and put them in that directory. | |
2. Create a file called equiv.cpp. Copy and paste the module-template into it. Edit the file. Add your name and the assignment number. If you will use tabs, say how far apart the tab stops are. Add line #include "equiv.h"
| |
3. Write a comment telling what this module will provide when it is finished. Equiv.cpp is not an application. It just provides a tool. Say that it is an equivalence relation manager and give an outline of the interface. | |
4. Create a file called equiv.h. Copy the following into equiv.h, then edit it to add your name.
Note. In the types of equivalent and leader, parameter R is not marked const, even though it seems to make sense to do that. The reason is that improvements that can be done for extra credit need to make changes to R, even in equivalent and leader. | |
5. In equiv.cpp, write a heading and contract, then fill in the body, of the 'newER' function. Notice that newER(n) returns an equivalence relation that can handle set {1, 2, , n}. Say that. Don't say that it returns an array. Where possible, express things in conceptual terms rather than in physical terms. | |
6. In equiv.cpp, write a contract, then an implementation, of the 'showER' function. Pay attention to what showER is supposed to do. | |
7. Create file test1.cpp for partial testing of equiv.cpp. Add a main function to test1.cpp and make main create a new ER object (using newER) and use showER to show what it looks like. Testequiv.cpp should contain #include "equiv.h"to allow it to use what is described in equiv.h.
Compile test1.cpp and equiv.cpp together as follows. g++ -Wall -o test1 test1.cpp equiv.cppThen run test1 by ./test1 | |
8. In equiv.cpp, write a heading and contract, then an implementation, of the 'leader' function. Modify test1.cpp so that it tests leader by showing showing the leader of each value in the ER object that it creates. Note that, at this point, each number will be its own leader. Run test1.cpp. | |
9. In equiv.cpp, write a heading and contract, then an implementation, of the 'merge' function. Modify test1.cpp by making it merge just a few values, then show what the equivalence relation looks like using showER. Does it look right? | |
10. In equiv.cpp, write a contract, then an implementation, of the 'equivalent' function. Now you have enough to use the automated tester. Run it. If there are errors, fix them. You can read testequiv.cpp to see what it is doing, but only change equiv.cpp to fix errors; changing the tester will not help since I will not use your modified tester when I grade your submission. | |
11. In equiv.cpp, write a contract, then an implementation, of the 'destroyER' function. | |
12. Check your program. Proofread your contracts. Look for spelling and grammatical errors. Ensure that you have paid attention to the issues to be aware of. | |
13. Submit your work. |
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started