ExerciseFocus
0. Alternating FactorialRecursion and defining one recursive function using another.
1. Recursively Processing ArraysRecursive initialization, transformation, aggregation, minimum, and maximum.
2. Grey CodesRecursion and two-dimensional arrays through grey-code generation.

Getting Started

Warning: You can't use loops for this Volume, sorry :(

In this volume, we’re going to disallow loops. The code you write in student.c should solve every exercise recursively. You may implement additional helper functions in student.c for every exercise.

Why? Typically, we’re very happy to let you use any parts of C you might know before CS1010, and we hate banning things. In this Volume’s case though, we want you to develop specific recursion skills that will help you later. Working with constraints also helps develop your problem solving mental muscles. Please bear with us for now and trust that limiting this approach right now is in your best interest.

0. Alternating Factorial

Focus

Recursion, alternate factorials, and defining one recursive function using another.

Introduction

Have you heard of an alternating factorial? No? Well, neither have we! Nonetheless, we’ll see how to implement it as basic recursion practise.

You are already familiar with the factorial function:

In this exercise, you will implement a variation called the alternate factorial, defined recursively as follows:

Hint

Pay attention to what our base case is here, as opposed to the original factorial function.

For example:

Your Task

  • Write your solution in the function:
long alt_factorial(int n)

Expected Behaviour

Your function should implement alternate factorial recursively. The input satisfies . Compute the result recursively from the input; pre-computing the solutions and storing them in a lookup table or hard-coding them is not allowed.

Running and Testing

  • To compile: run make
  • To run: run ./alt_factorial
  • To test: run make test
  • Input: The program reads a single integer from standard input and outputs the value of alt_factorial(n)

Examples

InputOutput
11
21
35
419
5101

Notes

  • Implement alt_factorial and any helper functions you need
  • Do not change the provided input-reading code or main

1. Recursively Processing Arrays

Focus

Recursion over arrays by repeatedly solving a smaller prefix.

Your Task

Open student.c, and you should see the following functions that you need to fill out.

#include <stddef.h>
#include <stdio.h>
 
void initialize_increasing(int values[], size_t length) {
  // TODO
}
 
void double_if_even(int values[], size_t length) {
  // TODO
}
 
bool are_all_odd_indices_positive(int values[], size_t length) {
  // TODO
}
 
int sum_elements(int values[], size_t length) {
  // TODO
}
 
size_t find_min_index(int values[], size_t length) {
  // TODO
}
 
int find_max(int values[], size_t length) {
  // TODO
}
 
double digits_to_double(int values[], size_t length) {
  // TODO
}
 
void swap_adjacent_pairs(int values[], size_t length) {
  // TODO
}
 
bool is_palindrome(int values[], size_t length) {
  // TODO
}

Note

You may implement additional functions as helpers if you wish.

Expected Behaviour

  • initialize_increasing should initialise the given array with values from up to

  • double_if_even should double each even-valued element in the given array, leaving odd-valued elements unchanged

  • are_all_odd_indices_positive should return true if every element at an odd index (, , , and so on) is strictly positive, and false otherwise. Return true if there are no odd indices. Do not modify the array

  • sum_elements should return the sum of all the elements

  • find_min_index should return the zero-based index of the smallest element. If the minimum occurs more than once, return its first index

  • find_max should return the largest element

  • digits_to_double should treat every element as a decimal digit and return the digits after a decimal point. For example, {1, 2, 3, 4} should produce . Every element will be between and

  • swap_adjacent_pairs should recursively swap the first and second elements, the third and fourth elements, and so on. If the array has an odd number of elements, leave the last element unchanged. For example, {1, 2, 3, 4, 5, 6} should become {2, 1, 4, 3, 6, 5}, and {1, 2, 3, 4, 5} should become {2, 1, 4, 3, 5}. Empty arrays and arrays with one element should remain unchanged

  • is_palindrome should return true if the array is palindromic, meaning its elements read the same forwards and backwards, and false otherwise. For example, {1, 2, 3, 2, 1} is palindromic, but {1, 2, 3} is not. Empty arrays and arrays with one element are palindromic. Do not modify the array

Constraints

  • length is the number of elements to process, at most
  • find_min_index and find_max always receive a nonempty array
  • Every doubled value in double_if_even fits in an int
  • Every intermediate and final sum in sum_elements fits in an int
  • Elements outside the specified length must remain unchanged

For an empty array (length == 0):

FunctionBehaviour
initialize_increasing, double_if_even, swap_adjacent_pairsLeave the array unchanged
sum_elementsReturn 0
digits_to_doubleReturn 0.0
are_all_odd_indices_positive, is_palindromeReturn true

Running and Testing

  • To compile: run make
  • To run: run ./recursive-arrays
  • To test: run make test

Run ./recursive-arrays, then type an operation, the number of elements, and that many elements. You may separate these with spaces or newlines. The operations are initialize, double, odd-positive, sum, min, max, to-double, swap-pairs, and palindrome. Input reading and printing has been handled for you.

For example, to test digits_to_double:

to-double
4
1 2 3 4

And in this case, the program should print:

0.1234

Press Enter after the final element to see the result. For an empty array, press Enter after the zero length; no elements are needed.

To run the tests for just one function, use its C function name, as in Volume 1’s Pong exercise:

make test FUNCTION=is_palindrome

Replace is_palindrome with any of the function names above to work on one function at a time. Run make test without FUNCTION to run all the cases. All functions must still compile, but only the selected function’s cases will run.

Examples

Type each example’s input into ./recursive-arrays. Boolean results are printed as true or false.

FunctionInputOutput
initialize_increasinginitialize 5 0 0 0 0 01 2 3 4 5
double_if_evendouble 5 3 -2 0 7 103 -4 0 7 20
are_all_odd_indices_positiveodd-positive 5 10 20 30 40 50true
sum_elementssum 5 4 7 2 -3 515
find_min_indexmin 5 4 7 2 -3 53
find_maxmax 5 4 7 2 -3 57
digits_to_doubleto-double 4 1 2 3 40.1234
swap_adjacent_pairsswap-pairs 5 1 2 3 4 52 1 4 3 5
is_palindromepalindrome 5 1 2 3 2 1true

2. Grey Codes

Focus

Recursion and two-dimensional arrays through grey-code generation.

Background

We’re going to get you to generate something called a grey code. You can read all about them here: https://en.wikipedia.org/wiki/Gray_code, they’re very cool, and some computer engineers we know have had to make these in their programs in the past. (We lied, we know a few electrical engineers who had to do it, but they worked at Intel, so we guess that counts!)

They’re used in quite a few engineering and mathematical contexts, but here’s what we basically want from you: Given an input , we need you to generate an array of arrays each with elements each being either only 0 or 1, such that:

  • All possible sequences of 0 and 1 are listed, each possibility on its own line
  • Any adjacent sequence differs only exactly by 1 character
  • The first sequence and last sequence also differ only exactly by 1 character

Example 1

Here’s an example for :

00
01
11
10

Explanation: There are possible sequences we need to output, notice here that each line differs from the next line in exactly 1 character only. Furthermore, the first line and the last line differ in exactly 1 character.

Example 2

Here’s an example for :

000
001
011
010
110
111
101
100

Explanation: There are possible sequences we need to output, notice here that each line differs from the next line in exactly 1 character only. Furthermore, the first line and the last line differ in exactly 1 character.

Note

The ordering of the sequences matter here! This is not the same as just printing out all possible sequences. Adjacent lines of output must differ by exactly 1 character.

Step 1.1: Identify the simple case

Think about what is a valid grey code for . That should be your base case.

Step 1.2: Use the solution to the simpler case to solve the current problem

Let’s say we could solve grey-code for . You might want to think about how that sequence helps you solve the case.

Step 2: Break the problem up into logical steps

Identify the high level idea without writing the code first. What kind of operations do you need? Can you make each of these steps their own functions? What should their prototypes be?

Step 3: Start Writing the Code

Hop to it!

Code

In student.c, complete the following function:

void grey_code(unsigned int n, GreyCode sequence[]) {
  // TODO
}
The GreyCode type

GreyCode sequence[] is an array of GreyCode. You are promised that sequence[] is an array that can hold at least elements. Use only the first rows. You are also promised that each element is an array that will fit at least n elements. I.e. GreyCode is an array.

I.e. you could choose to think of sequence as a 2D array, with rows and columns.

Indexing

If for example, you wish to set the character of the sequence to be 1, you’d write: sequence[j][i] = '1'.

Your Task

Complete grey_code recursively. Do not use loops. Fill the first rows of sequence, each with exactly characters, either '0' or '1' (subject to the requirement).

Any ordering satisfying all the stated grey-code properties is accepted; it need not match the examples exactly.

The input satisfies (anything larger and the output is gonna be really long anyway). Generate the sequences recursively from the input; pre-computing the solutions and storing them in lookup tables or hard-coding them is not allowed.

Running and Testing

  • To compile: run make
  • To run: run ./grey-code
  • To test: run make test
  • Input: Input a single integer from to , inclusive

Suggestions / Hints