NivaarExam PrepOfficial exam papers ↗

25-Comp-A4 Program Design and Data Structures · May 2016

Question 6 of 8: File I/O — Names Common to Three Sorted Files

Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)

Notes on this paper

Paper format. 98-Comp-A4 Program Design and Data Structures, May 2016 — 3 hours, closed book, no calculator permitted. Eight questions of equal weight (20 marks each: some split as (a) 10 + (b) 10); candidates answer any five, so a complete paper is 100 marks. Pseudocode or any high-level language is accepted, and the examiner's note states explicitly that marking emphasises the operation of the program, not syntactic details. All eight questions are answered below, because the whole set is the more useful revision resource. Answers are given in C or C++ as the question dictates; each is compilable as written, but a clear, correctly reasoned pseudocode answer would earn the same marks.

Reference texts for this subject.

  • Cormen, Leiserson, Rivest & Stein, Introduction to Algorithms, 4th ed. — tree traversals (ch. 12), sorting and Quicksort (ch. 7), asymptotic analysis (ch. 3).
  • Weiss, Data Structures and Algorithm Analysis in C, 2nd ed. — linked lists (ch. 3), binary search trees (ch. 4).
  • Deitel & Deitel, C++ How to Program, 10th ed. — class design and templates (ch. 9–12), file streams (ch. 14).
  • Kernighan & Ritchie, The C Programming Language, 2nd ed. — character/array I/O idioms (ch. 1, 7), pointers and structures (ch. 5–6).
  • Stroustrup, The C++ Programming Language, 4th ed. — class templates and value semantics (ch. 3, 25–27).

The Computer Engineering citation list is built around architecture and networking texts (Patterson & Hennessy, Tanenbaum, Mano); this subject is programming and data structures, so the works above are cited instead.

Question 6: File I/O — Names Common to Three Sorted Files (20 marks)

Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.

Given. Three text files, each already sorted alphabetically, one name per line in Last, First format, of unknown and possibly differing length.

Find. A program that prints exactly the names appearing in all three files.

Approach. Since all three files are already sorted, a single synchronized three-pointer scan (analogous to a 3-way merge) finds the intersection in one pass over all three files combined — no need to load any file fully into memory, and no need to sort anything, since sorting has already been done for us.

  1. Generalize two-way merge-intersection to three files. At each step, look at the current line of all three files. If all three are equal, that name is common to all three — print it and advance all three files. Otherwise, whichever file(s) hold the alphabetically smallest current line cannot possibly match the other two (since all files are sorted ascending, that name will never recur later in the other files), so only those file(s) advance.
  2. Write the program. A fixed-size line buffer is sufficient since names are short; strcmp gives the needed lexicographic ordering directly on the "Last, First" strings.
    #include <stdio.h>
    #include <string.h>
    
    #define LINE_LEN 128
    
    /* Reads one line, stripping the trailing newline. Returns 0 at EOF. */
    int readLine(FILE *fp, char *buf)
    {
        if (fgets(buf, LINE_LEN, fp) == NULL)
            return 0;
        buf[strcspn(buf, "\n")] = '\0';
        return 1;
    }
    
    int main(void)
    {
        char nameA[LINE_LEN], nameB[LINE_LEN], nameC[LINE_LEN];
        char fa[100], fb[100], fc[100];
        FILE *A, *B, *C;
    
        printf("Enter the three file names: ");
        scanf("%99s %99s %99s", fa, fb, fc);
        A = fopen(fa, "r");  B = fopen(fb, "r");  C = fopen(fc, "r");
        if (!A || !B || !C) { printf("Could not open all three files.\n"); return 1; }
    
        int haveA = readLine(A, nameA);
        int haveB = readLine(B, nameB);
        int haveC = readLine(C, nameC);
    
        while (haveA && haveB && haveC) {
            int ab = strcmp(nameA, nameB);
            int bc = strcmp(nameB, nameC);
            int ac = strcmp(nameA, nameC);
    
            if (ab == 0 && bc == 0) {          /* all three equal */
                printf("%s\n", nameA);
                haveA = readLine(A, nameA);
                haveB = readLine(B, nameB);
                haveC = readLine(C, nameC);
            } else {
                /* advance every file tied for the SMALLEST current line -- that
                   name can never reappear later in the other two files */
                if (ab <= 0 && ac <= 0) haveA = readLine(A, nameA);
                if (ab >= 0 && bc <= 0) haveB = readLine(B, nameB);
                if (ac >= 0 && bc >= 0) haveC = readLine(C, nameC);
            }
        }
    
        fclose(A); fclose(B); fclose(C);
        return 0;
    }
    The advance rule keeps whichever file(s) already hold the current largest line untouched, and steps every file tied for smallest — which is what correctly handles a three-way tie between exactly two of the files without either stalling or over-advancing.
  3. Confirm on a worked example. With advisors = {Adams,Ray; Chen,Amy; Diaz,Ivy; Ng,Tom; Ortiz,Bea}, traders = {Chen,Amy; Diaz,Ivy; Kim,Sam; Ortiz,Bea; Zong,Uma}, rolodex = {Bell,Uri; Chen,Amy; Ortiz,Bea; Ortiz,Cid; Ryan,Max}, the synchronized scan reports exactly the two names present in all three lists. $$\boxed{\text{common names} = \{\text{Chen, Amy};\ \text{Ortiz, Bea}\}}$$
Question 6 — results
QuantityValue
Names common to all three example filesChen, Amy; Ortiz, Bea
File comparisons per synchronized step3 (pairwise strcmp of the current lines)
Total time complexity$O(n_A+n_B+n_C)$ — each file read once
Any input file emptyLoop condition false immediately; prints nothing