NivaarExam PrepOfficial exam papers ↗

25-Comp-A4 Program Design and Data Structures · December 2019

Question 5 of 9: File I/O — Merging Two Sorted Files

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

Notes on this paper

Paper format. 17-Comp-A4 Program Design and Data Structures, December 2019 — 3 hours, closed book, no calculator permitted. Nine questions, each of equal weight (Questions 1, 2, 7 and 8 are split 10+10; Questions 3–6 and 9 are 20 marks each), so 180 marks are printed in total. The cover page directs candidates to answer any six of the nine, and only the first six as they appear in the answer book are marked — so a complete paper is $6\times 20 = 120$ marks, which is the "total mark is out of 120" the paper's Note 6 states. Pseudocode or any high-level language (e.g. C or C++) is accepted, and the examiner's note states explicitly that marking emphasises the operation of the program, not syntactic details. All nine 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 walks (ch. 12), sorting and its complexity (ch. 2, 7), asymptotic analysis (ch. 3).
  • Weiss, Data Structures and Algorithm Analysis in C, 2nd ed. — arrays (ch. 1), linked lists (ch. 3), binary trees (ch. 4), searching and hashing (ch. 5).
  • Deitel & Deitel, C++ How to Program, 10th ed. — class design and operator overloading (ch. 9–11), file streams (ch. 14).
  • Kernighan & Ritchie, The C Programming Language, 2nd ed. — character/file I/O idioms (ch. 1, 7), pointers and structures (ch. 5–6).
  • Stroustrup, The C++ Programming Language, 4th ed. — value semantics, const-correctness and operator overloading (ch. 3, 11).

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 5: File I/O — Merging Two 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.

Strategy. This is the merge step of merge sort applied to two files instead of two in-memory arrays: since both inputs are already individually sorted, the smallest not-yet-written record overall is always one of the two records currently "at the front" of the two files, so the program never needs to hold more than one record from each file in memory at a time. It reads one record from each file, repeatedly writes whichever of the two current records is lexicographically smaller and refills only that side, and once one file is exhausted it copies the remainder of the other file straight through (their relative order is already correct, and every one of those remaining records is $\ge$ everything already written, since the exhausted file's last record was still $\le$ the still-open file's current record at the moment it ran out).

Given. Two files, each pre-sorted line by line (records up to 80 characters including the newline); a third output filename.

Find. One output file containing all records from both inputs in sorted order.

  1. Write the merge.
    #include <stdio.h>
    #include <string.h>
    
    #define MAXREC 81   /* 80 chars including '\n', plus '\0' */
    
    int main(void)
    {
        char nameA[256], nameB[256], nameOut[256];
        char recA[MAXREC], recB[MAXREC];
        FILE *fa, *fb, *fout;
        int haveA, haveB;
    
        printf("Enter first sorted file: ");  scanf("%255s", nameA);
        printf("Enter second sorted file: "); scanf("%255s", nameB);
        printf("Enter output file: ");        scanf("%255s", nameOut);
    
        fa = fopen(nameA, "r");
        fb = fopen(nameB, "r");
        fout = fopen(nameOut, "w");
        if (!fa || !fb || !fout) { printf("Could not open a file.\n"); return 1; }
    
        haveA = (fgets(recA, MAXREC, fa) != NULL);   /* "front" record of file A */
        haveB = (fgets(recB, MAXREC, fb) != NULL);   /* "front" record of file B */
    
        while (haveA && haveB) {
            if (strcmp(recA, recB) <= 0) {
                fputs(recA, fout);
                haveA = (fgets(recA, MAXREC, fa) != NULL);
            } else {
                fputs(recB, fout);
                haveB = (fgets(recB, MAXREC, fb) != NULL);
            }
        }
        /* copy whatever remains of whichever file is not yet exhausted */
        while (haveA) { fputs(recA, fout); haveA = (fgets(recA, MAXREC, fa) != NULL); }
        while (haveB) { fputs(recB, fout); haveB = (fgets(recB, MAXREC, fb) != NULL); }
    
        fclose(fa); fclose(fb); fclose(fout);
        return 0;
    }
  2. Trace it on two small sorted files. File A = {apple, cherry, mango, zebra}, File B = {banana, date, fig, kiwi, yam} (5 records – deliberately a different count from A, since the files may differ in length). Merging compares the two front records repeatedly: apple < banana (take A), banana < cherry (take B), cherry < date (take A), date < mango (take B), fig < mango (take B), kiwi < mango (take B), mango < yam (take A), yam < zebra (take B) — at which point B is exhausted, and the second drain loop copies A's one remaining record, zebra, straight through. Nine comparisons-and-writes for $4+5=9$ records, matching the $m+n$ output-step count: $$\boxed{\text{output} = \text{apple, banana, cherry, date, fig, kiwi, mango, yam, zebra}}$$
Question 5 — results
InputRecords
File A (sorted)apple, cherry, mango, zebra
File B (sorted)banana, date, fig, kiwi, yam
Merged output (sorted)apple, banana, cherry, date, fig, kiwi, mango, yam, zebra