In main function I calls the Choice function. The goal is to choose the sort type with the order of increase or decrease.
I calls Choice to receive the address of two IsBigger and Interchange functions.
Here is the code
#include <iostream>
using namespace std;
template <class T>
void Swap(T *a, T *b)
{
T temp = *a;
*a = *b;
*b = temp;
}
template <class T>
void Interchange(T a[], int n, bool(*Cmp)(T, T))
{
for (int i = 0; i < n - 1; i++)
for (int j = i + 1; j < n; j++)
if (Cmp(a[i], a[j]))
Swap(&a[i], &a[j]);
}
template <class T>
void Insertion(T a[], int n, bool(*Cmp)(T, T))
{
int x, j;
for (int i = 0; i < n; i++)
{
x = a[i]; j = i - 1;
while (j >= 0 && !Cmp(a[j],x))
{
a[j + 1] = a[j];
j--;
}
a[j + 1] = x;
}
}
template <class T>
bool IsBigger(T a, T b)
{
return a > b;
}
template <class T>
void Choice(T a[], int n, bool(*Cmp)(T, T), void(*Sort)(T*, int, bool*))
{
Sort(a, n, Cmp);
}
int main()
{
int a[] = { 3,4,1,5 };
Choice<int>(a, 4, &IsBigger, &Interchange);
return 0;
}
In main function, function Choice has error when it calls IsBigger and Interchange. The error is "no instance of function template "Choice" matches the argument list"
I don't know what am I wrong. Please help me. Thanks a lot
Related
Im trying to write some code that could sort an array using heapsort. The heap have two children right now but i want the user to be able to choose the amount of children in the heap(d in the function heapsort).
Question: How do i make the function heapsort able to recieve a number (d) from the user and sort the array with heapsort with that amount of children?
template <typename T>
void heapify(T arr[], int n, int i) {
int biggest = i;
int leftChild = 2 * i + 1;
int rightChild = 2 * i + 2;
if (leftChild < n && arr[leftChild] > arr[biggest])
{
biggest = leftChild;
}
if (rightChild < n && arr[rightChild] > arr[biggest]) {
biggest = rightChild;
}
if (biggest != i) {
swap(arr[i], arr[biggest]);
heapify(arr, n, biggest);
}
}
template <typename T>
void heapsort(T arr[], int n, int d)
{
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, n, i);
}
for (int i = n - 1; i > 0; i--) {
swap(arr[0], arr[i]);
heapify(arr, i, 0);
}
}
Just because you made it so easy:
template <typename T>
void heapify(T arr[], int n, int d, int i) {
int biggest = i;
int childrenStart = d * i + 1;
int childrenEnd = childrenStart + d;
if (childrenEnd > n) {
childrenEnd = n;
}
for (int child = childrenStart; child < childrenEnd; ++child) {
if (arr[child] > arr[biggest]) {
biggest = child;
}
}
if (biggest != i) {
swap(arr[i], arr[biggest]);
heapify(arr, n, d, biggest);
}
}
template <typename T>
void heapsort(T arr[], int n, int d)
{
if (n<=0) {
return;
}
for (int i = (n-2) / d; i >= 0; i--) {
heapify(arr, n, d, i);
}
for (int i = n - 1; i > 0; i--) {
swap(arr[0], arr[i]);
heapify(arr, i, d, 0);
}
}
Basically what I want to do is assign a function inside a for loop nest ONCE with a template. My current approach calls onto a vector of functions (see below), but this is expensive because the function is called on every loop:
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <bits/stdc++.h>
int func0(int k, int j, int i) {int that{(j + 2) + ( i) + k}; return that; }
int func1(int k, int j, int i) {int that{(i + 2) + (k) + j}; return that; }
int func2(int k, int j, int i) {int that{(k + 2) + ( k) + i}; return that; }
int func3(int k, int j, int i) {int that{(j + j) + (j) + i}; return that; }
void myfunction(int idx)
{
int (*funcs[])(int k, int j, int i) =
{func0, func1, func2, func3};
int N = 10;
int value;
for (int k = 0; k < N; k++)
for (int j = 0; j < N; j++)
for (int i = 0; i < N; i++)
{
value = funcs[idx](k, j, i); // this makes a call to func of index idx ON EVERY LOOP
printf("%d ", value);
std::cout << value;
}
}
int main()
{
int k=0; int k2 =0;
while (k < 100){
myfunction(k2);
k++; k2++;
k2%=4;
}
}
I would like funcs to be a template rather than a vector. My other option is to define a myfunction() for every func, but this makes for too much code. Any help is appreciated.
I'm working with Template Functions and am looking to create one that sorts both ints and strings. I have managed to get it working with ints but having trouble with strings.
Here is my code so far.
#include <iostream>
#include <string>
using namespace std;
template <class T>
void print(T arr[], int n);
template <class T>
void swap(T arr[], int i, int j);
template <class T>
T getSmallest(T arr[], int start, int end);
template <class T>
void selectionSort(T arr[], int n);
int main()
{
int n = 10;
int iarr[] = { 3,5,9,2,1,7,8,4,0,6 };
selectionSort<int>(iarr, n);
print<int>(iarr, n);
cout << endl;
string sarr[] = { "skunk", "hedgehog", "aardvark", "zebra", "rat", "cat", "hippopotamus", "hamster", "manatee", "red panda" };
selectionSort<string>(sarr, n);
print<string>(sarr, n);
cout << endl;
return 0;
}
// PRE: length of arr = n
// PARAM: arr = array of integers of length n
// POST: prints arr[0:n]
template <class T>
void print(T arr[], int n) {
for (int i = 0; i < n; i++) {
cout << arr[i] << endl;
}
}
// PRE: i, j < length of arr
// PARAM: arr = array of integers of length n, i and j are indexes
// POST: swaps arr[i] with arr[j]
template <class T>
void swap(T arr[], int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// PRE: 0 <= start < end <= length of arr
// PARAM: arr = array of integers
// start = start index of sub-array
// end = end index of sub-array + 1
// POST: returns index of smallest value in arr{start:end}
template <class T>
T getSmallest(T arr[], int start, int end) {
T smallest = start;
for (int i = start + 1; i < end; ++i) {
if (arr[i] < arr[smallest]) {
smallest = i;
}
}
return smallest;
}
// PRE: length of arr = n
// PARAM: arr = array of integers of length n
// POST: sorts arr in ascending order
template <class T>
void selectionSort(T arr[], int n) {
for (int i = 0; i < n - 1; ++i) {
int smallest = getSmallest(arr, i, n);
swap(arr, i, smallest);
}
}
I know I need to find some way to make "smallest" somehow able to work for strings. But simply turning it from int to template T isn't working. Any suggestions?
You almost have it.
The only thing off is that getSmallest() returns an index regardless of what T is. So that part should not be templated.
template <class T>
int getSmallest(T arr[], int start, int end) {
int smallest = start;
This function
template <class T>
T getSmallest(T arr[], int start, int end) {
T smallest = start;
for (int i = start + 1; i < end; ++i) {
if (arr[i] < arr[smallest]) {
smallest = i;
}
}
return smallest;
}
has an invalid return type. For an array of objects of the type std::string it will have the return type std::string.
It should look like
template <class T>
int getSmallest(T arr[], int start, int end) {
int smallest = start;
for (int i = start + 1; i < end; ++i) {
if (arr[i] < arr[smallest]) {
smallest = i;
}
}
return smallest;
}
Do not forget to change also the function template declaration
template <class T>
int getSmallest(T arr[], int start, int end)
You changed to many int to T.
template <class T>
T getSmallest(T arr[], int start, int end) {
T smallest = start;
for (int i = start + 1; i < end; ++i) {
if (arr[i] < arr[smallest]) {
smallest = i;
}
}
return smallest;
}
If you use int for the index then smallest should be int and the return type should be int, not T. Actually I suggest to use size_t for indices (unless you want to pass iterators):
template <class T>
size_t getSmallest(T arr[], size_t start, size_t end) {
size_t smallest = start;
for (size_t i = start + 1; i < end; ++i) {
if (arr[i] < arr[smallest]) {
smallest = i;
}
}
return smallest;
}
I'm wondering how can i do something like this ? Using template<typename T> with typedef ?
template <typename T>
typedef bool (*cmp_func)(T i0, T i1); // <- syntax error here
I'm trying to sort items of a template type.
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <string>
#include <cmath>
#include <ctime>
using namespace std;
typedef bool (*cmp_func)(int i0, int i1);
template<typename T>
void print_array(int n, T *x)
{
cout << "[";
for (int i = 0; i < n; ++i) {
cout << setw(3) << x[i];
}
cout << " ]\n";
}
template <typename T>
bool less_than(T i0, T i1) { return i0 < i1; }
template <typename T>
bool greater_than(T i0, T i1) { return i0 > i1; }
template <typename T>
bool is_sorted(int n, T *x, cmp_func cmp)
{
for (int i = 1; i < n; ++i)
if ((*cmp)(x[i], x[i-1]))
return false;
return true;
}
template <typename T>
void exchange(T* x, int i, int j)
{
T t = x[i];
x[i] = x[j];
x[j] = t;
}
template <typename T>
void insertion_sort(T *x, int l, int r, cmp_func cmp)
{
for (int i = l+1; i <= r; ++i) {
for (int j = i; j > l; --j){
if ((*cmp)(x[j], x[j-1]))
exchange(x, j, j-1);
cout << " ";
print_array(r-l+1, x+l);
}
}
}
template <typename T>
void insertion_sort2(T *x, int l, int r, cmp_func cmp)
{
for (int i = r; i > l; --i)
if ((*cmp)(x[i], x[i-1]))
exchange(x, i, i-1);
for (int i = l+2; i <= r; ++i) {
int j = i;
int v = x[i];
while((*cmp)(v, x[j-1])) {
x[j] = x[j-1];
--j;
}
x[j] = v;
cout << " ";
print_array(r-l+1, x+l);
}
}
template <typename T>
void fill_random(T n, T *x)
{
const int M = 100;
srand(time(0));
for (int i = 0; i < n; ++i)
x[i] = rand() % M;
}
int main(int argc, char **argv)
{
const int N = 10;
int x[N];
fill_random(N, x);
print_array(N, x);
insertion_sort(x, 0, N-1, &less_than);
print_array(N, x);
if (is_sorted(N, x, &less_than))
cout << "SORTED\n";
else
cout << "NOT SORTED\n";
return EXIT_SUCCESS;
}
Typedefs cannot be templates. C++11 using aliases, however, can be:
template <typename T>
using cmp_func = bool (*)(T i0, T i1);
The pre-C++11 workaround is to create a template struct that has a type typedef:
template <typename T>
struct cmp_func {
typedef bool (*type)(T i0, T i1);
};
Which is then referenced as typename cmp_func<int>::type for example.
I posted last night about an array class, and now I'm having trouble with a sorting class. About half of the functions are defined, either by the professor or by the algorithms he gave us, but a lot of the definitions are confusing me. I'm not sure what makes them any different from the ones above it.
#ifndef SORTS_H
#define SORTS_H
#include <iostream>
#include <string>
#include "Array.h"
using namespace std;
template <class T>
void insertionSort(Array<T> &a);
template <class T>
void selectionSort(Array<T> &a);
template <class T>
void selectionSort(T a[], int n);
template <class T>
void mergesort(T *input, int size);
template <class T>
void mergesort(T *input, int left, int right, T *scratch);
template <class T>
T less(T x, T y);
template <class T>
void mergesort(Array<T> &input, int left, int right, Array<T>&scratch);
template <class T>
void mergesort(Array<T> & input);
Array<int> & random(int n);
template <class T>
void selectionSort(T a[], int n) {
int i, j, tmp;
int min_idx = 0;
for (size_t i = 0; i < n-1; i++) {
min_idx = i;
for (size_t j = i+1; j < n; j++) {
if (a[j] < a[min_idx]) {
min_idx = j;
}
tmp = a[i];
a[i] = a[min_idx];
a[min_idx] = tmp;
}
}
}
template <class T>
void selectionSort(Array<T> &a) {
int tmp;
int min_idx = 0;
for (int i = 0; i < a.getSize() - 1; i++) {
min_idx = i;
for (int j = i + 1; j < a.getSize(); j++) {
if (a[j] < a[min_idx]) {
min_idx = j;
}
tmp = a[i];
a[i] = a[min_idx];
a[min_idx] = tmp;
}
}
}
template <class T>
void insertionSort(Array<T> &a) {
// put your code here
}
template <class T>
bool sorted(Array<T> a) {
for (int i = 1; i < a.getSize(); i++)
if (a[i - 1] > a[i]) return false;
return true;
}
Array<int> & random(int n) {
Array<int> *tmp = new Array<int>(n);
for (int i = 0; i < n; i++)
(*tmp)[i] = rand() % 1000;
return *tmp;
}
template <class T>
T less(T x, T y) {
if (x < y) {
return x;
}
else {
return y;
}
}
template <class T>
void mergesort(T *input, int left, int right, T *scratch) {
if (right == left + 1) {
return;
}
else {
int i = 0;
int length = right - left;
int midpoint_distance = length / 2;
int l = left, r = left + midpoint_distance;
mergesort(input, left, left + midpoint_distance, scratch);
mergesort(input, left + midpoint_distance, right, scratch);
/* merge the arrays together using scratch for temporary storage */
for (i = 0; i < length; i++) {
/* Check to see if any elements remain in the left array; if so,
* we check if there are any elements left in the right array; if
* so, we compare them. Otherwise, we know that the merge must
* use take the element from the left array */
if (l < left + midpoint_distance &&
(r == right || min(input[l], input[r]) == input[l])) {
scratch[i] = input[l];
l++;
}
else {
scratch[i] = input[r];
r++;
}
}
/* Copy the sorted subarray back to the input */
for (i = left; i < right; i++) {
input[i] = scratch[i - left];
}
}
}
template <class T>
void mergesort(T *input, int size) {
int *scratch = new int[size];
mergesort(input, 0, size, scratch);
delete [] scratch;
}
template <class T>
void mergesort(Array<T> &input, int left, int right, Array<T>&scratch) {
if (right == left + 1) {
return;
}
else {
int i = 0;
int length = right - left;
int midpoint_distance = length / 2;
int l = left, r = left + midpoint_distance;
mergesort(input, left, left + midpoint_distance, scratch);
mergesort(input, left + midpoint_distance, right, scratch);
/* merge the arrays together using scratch for temporary storage */
for (i = 0; i < length; i++) {
/* Check to see if any elements remain in the left array; if so,
* we check if there are any elements left in the right array; if
* so, we compare them. Otherwise, we know that the merge must
* use take the element from the left array */
if (l < left + midpoint_distance &&
(r == right || min(input[l], input[r]) == input[l])) {
scratch[i] = input[l];
l++;
}
else {
scratch[i] = input[r];
r++;
}
}
/* Copy the sorted subarray back to the input */
for (i = left; i < right; i++) {
input[i] = scratch[i - left];
}
}
}
template <class T>
void mergesort(Array<T> &input) {
// put your code here
}
#endif
I also noticed that there is a void insertionSort(Array<T> &a); function, but the algorithm I was given is:
void insertionSort(int a[], int n){
int tmp;
int i, j;
for (i = 1; i < n; i++) {
tmp = a[i];
for (j = i - 1; j >= 0; j--)
if (a[j] > tmp) a[j + 1] = a[j];
else break;
a[j + 1] = tmp;
}
}
Am I supposed to implement this the same way, just replacing int a[] with, say... &arr? I'm guessing since this includes array.h and the array class has T * arr;, I should be pointing to the address of that array? Would this also work for each definition that has the address operator in its parameter?
The difference is one, as you say, takes a typical int array a[], but how would you know the size? So this version requires the user to send it to the function with n as the number of elements. In your Array class you provide a size so there's no need for it. In general you're providing overloads for multiple situations.
I'm not sure what you mean by replacing int a[] w/ &arr, the signature is there, use what was given to you unless you're supposed to change it.
If you go back to your question about the Array class you can see an answer which uses the reference just as you would normally, i.e,
template <class T>
Array<T>::Array(const Array &other) : size(other.size), arr(new T[size])
{ // ^^^^^^
for (int i = 0; i < size; ++i)
arr[i] = other.arr[i];
} // ^^^^^
now apply it to this situation.
Also,
template <class T>
void selectionSort(Array<T> &a) {
// I'm not sure I understand what this is supposed to do that's different from the above selectionSort.
// I know that & is the reference operator, so should I just return whatever &a is?
}
You won't be returning anything here considering void as the return and the use of the reference. You pass by reference as opposed to by value so that what you do in the function is persistent. You could choose to pass back the sorted array and not use a reference but I'm fairly certain it'd be slower overall considering the assignment and copy. That's why the example from your other question is using const Array &other. It prevents the entire array, which may be large, from being copied and sent to the function as well as being changed.