about summary refs log tree commit diff
path: root/usth/ICT2.1/labwork/5
diff options
context:
space:
mode:
Diffstat (limited to 'usth/ICT2.1/labwork/5')
-rw-r--r--usth/ICT2.1/labwork/5/Ex1.c58
-rw-r--r--usth/ICT2.1/labwork/5/Ex2.c74
-rw-r--r--usth/ICT2.1/labwork/5/README.pdfbin0 -> 256485 bytes
-rw-r--r--usth/ICT2.1/labwork/5/README.tex143
-rw-r--r--usth/ICT2.1/labwork/5/TT5.pdfbin0 -> 465238 bytes
-rw-r--r--usth/ICT2.1/labwork/5/construct.c27
-rw-r--r--usth/ICT2.1/labwork/5/construct.h15
7 files changed, 317 insertions, 0 deletions
diff --git a/usth/ICT2.1/labwork/5/Ex1.c b/usth/ICT2.1/labwork/5/Ex1.c
new file mode 100644
index 0000000..e64c6ea
--- /dev/null
+++ b/usth/ICT2.1/labwork/5/Ex1.c
@@ -0,0 +1,58 @@
+/*
+ * Cocktail shaker sorting integers from stdin
+ * Copyright (C) 2019,  Nguyễn Gia Phong
+ * This software is licenced under a CC BY-SA 4.0 license
+ */
+
+#include <stdio.h>
+
+void strswap(char *this, char *that, size_t n)
+{
+	while (n--) {
+		this[n] ^= that[n];
+		that[n] ^= this[n];
+		this[n] ^= that[n];
+	}
+}
+
+void csort(void *base, size_t nmemb, size_t size,
+           int (*compar)(const void *, const void *))
+{
+	char *i, *low = base;
+	char *high = low + nmemb * size;
+	do {
+		char *h = i = low;
+		while ((i += size) < high)
+			if (compar(i - size, i) > 0)
+				strswap(i - size, h = i, size);
+		high = h;
+		if (low + size >= high)
+			break;
+		char *l = i = high;
+		while ((i -= size) > low)
+			if (compar(i - size, i) > 0)
+				strswap(i - size, l = i, size);
+		low = l;
+	} while (low + size < high);
+}
+
+int cmp(const void *x, const void *y)
+{
+	return *(int *) x - *(int *) y;
+}
+
+int main()
+{
+	size_t n;
+	scanf("%zu", &n);
+	int a[n];
+	for (int i = 0; i < n; i++)
+		scanf("%d", a + i);
+
+	csort(a, n, sizeof(int), cmp);
+	for (int i = 0; i < n; i++)
+		printf("%d ", a[i]);
+	putchar(10);
+
+	return 0;
+}
diff --git a/usth/ICT2.1/labwork/5/Ex2.c b/usth/ICT2.1/labwork/5/Ex2.c
new file mode 100644
index 0000000..edb5c26
--- /dev/null
+++ b/usth/ICT2.1/labwork/5/Ex2.c
@@ -0,0 +1,74 @@
+/*
+ * Merge sorting integers from stdin
+ * Copyright (C) 2019,  Nguyễn Gia Phong
+ * This software is licenced under a CC BY-SA 4.0 license
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "construct.h"
+
+construct *merge(construct *left, construct *right,
+                 int (*compar)(const void *, const void *))
+{
+	if (left == NULL)
+		return right;
+	if (right == NULL)
+		return left;
+	if (compar(car(left), car(right)) <= 0)
+		return cons(car(left), merge(cdr(left), right, compar));
+	return cons(car(right), merge(left, cdr(right), compar));
+}
+
+construct *msort(construct *list, int (*compar)(const void *, const void *))
+{
+	construct *rest, *left = NULL, *right = NULL;
+	while (list != NULL) {
+		left = cons(car(list), left);
+		rest = cdr(list);
+		if (rest == NULL)
+			break;
+		right = cons(car(rest), right);
+		list = cdr(rest);
+	}
+	if (left == NULL)
+		return right;
+	if (right == NULL)
+		return left;
+	return merge(msort(left, compar), msort(right, compar), compar);
+}
+
+int cmp(const void *x, const void *y)
+{
+	return *(int *) x - *(int *) y;
+}
+
+construct *iread(size_t n)
+{
+	if (!n)
+		return NULL;
+	int *tmp = malloc(sizeof(int));
+	scanf("%d", tmp);
+	return cons(tmp, iread(n - 1));
+}
+
+void iprint(construct *list)
+{
+	if (list == NULL) {
+		putchar(10);
+	} else {
+		printf("%d ", *(int *) car(list));
+		iprint(cdr(list));
+	}
+}
+
+int main()
+{
+	size_t n;
+
+	scanf("%zu", &n);
+	iprint(msort(iread(n), cmp));
+
+	return 0;
+}
diff --git a/usth/ICT2.1/labwork/5/README.pdf b/usth/ICT2.1/labwork/5/README.pdf
new file mode 100644
index 0000000..8a94167
--- /dev/null
+++ b/usth/ICT2.1/labwork/5/README.pdf
Binary files differdiff --git a/usth/ICT2.1/labwork/5/README.tex b/usth/ICT2.1/labwork/5/README.tex
new file mode 100644
index 0000000..4c71999
--- /dev/null
+++ b/usth/ICT2.1/labwork/5/README.tex
@@ -0,0 +1,143 @@
+\documentclass[a4paper,12pt]{article}
+\usepackage[english,vietnamese]{babel}
+\usepackage{amsmath}
+\usepackage{hyperref}
+\usepackage{lmodern}
+\usepackage{mathtools}
+
+\title{Algorithms and Data Structures\\ Searching and Sorting}
+\author{Nguyễn Gia Phong---BI9-184}
+\date{\dateenglish\today}
+
+\begin{document}
+\maketitle
+\section{Cocktail Shaker Sort}
+The code is implemented following the cocktail shaker sort's
+pseudocode\footnote{\url{https://en.wikipedia.org/wiki/Cocktail\_shaker\_sort\#Pseudocode}}
+with bubble sort's optimization\footnote{\url{https://en.wikipedia.org/wiki/Bubble\_sort\#Optimizing\_bubble\_sort}}
+whose time complexity is analyzed as follows
+
+\subsection{Best Case}
+For the matter of brevity, we consider all operations on the array's $n$ members
+are in constant time ($\Theta(1)$).  If the array is already sorted, after
+the first \verb|while| loop (line 25), \verb|h| is still \verb|low| and thus
+the \verb|do|--\verb|while| loop is broken.  Since the while loop runs from
+\verb|low + size| to \verb|high - size| by \verb|size| steps, the running time
+is \verb|(high - low - size*2)/size + 1| or \verb|nmemb - 1|.  Therefore
+the best case time complexity is $\Omega(n - 1) = \Omega(n)$.
+
+\subsection{Average Case}
+Assume the average case is when the array is uniformly shuffled, that is,
+every permutation has the equal probability to occur.
+
+Given a permutation of an $n$-element array, consider the positive integer
+$k \le n$ that exactly the last $n - k$ members are continuously in the
+correct positions (as in the ascendingly sorted array).  It is obvious that
+for $k = 1$, the array is sorted and the probability of the permutation
+to appear is $1/n!$.  For $1 < k \le n$, if we fix the last $n - k$ members
+in their right places, out of the $k!$ permutations of the first $k$ elements,
+$(k - 1)!$ ones has the $k$-th greatest at the correct place.  Therefore,
+let $X$ be the number that exactly $n - X$ last elements are in
+the right positions, we have
+\[p_X(k) = \begin{dcases}
+  \frac{1}{n!} &\text{if }k = 1\\
+  \frac{k! - (k - 1)!}{n!} &\text{otherwise}
+\end{dcases}\]
+
+Applying this to the first \verb|while| (line 25) with $n$ and $X - 1$ being
+the number of steps from \verb|low| to \verb|high|, before and after
+\verb|high = h| respectively, the expectation of $X$ is
+\begin{align*}
+  \mathbf E[X] &= \sum_{k=1}^n k p_X(k)\\
+  &= \frac{1}{n!} + \sum_{k=2}^n\frac{k!k - k!}{n!}\\
+  &= \frac{1}{n!} + \sum_{k=3}^{n+1}\frac{k!}{n!}
+   - \sum_{k=2}^n\frac{k!}{n!} - \sum_{k=2}^n\frac{k!}{n!}\\
+  &= \frac{1}{n!} + \frac{(n+1)!}{n!}
+   - \frac{2!}{n!} - \sum_{k=2}^n\frac{k!}{n!}\\
+  &= n + 1 - \sum_{k=1}^n\frac{k!}{n!}\\
+  &= n - \sum_{k=1}^{n-1}\frac{k!}{n!}
+\end{align*}
+
+Hence after line 28, the newly sorted length of the array is
+\[n - \mathbf E[X - 1] = n - \mathbf E[X] + 1
+  = 1 + \sum_{k=1}^{n-1}\frac{k!}{n!} = \Theta(1)\]
+
+Similarly, line 31 to 35 also sort $\Theta(1)$ element(s), thus each iteration
+of the \verb|do|--\verb|while| loop to sort $\Theta(1)$ members. The overall
+average-case time complexity is
+\begin{align*}
+  T(n) &= \begin{dcases}
+    (n - \Theta(1)) + (n - \Theta(1)) + T(n - \Theta(1)) &\text{if }n > 0\\
+    \Theta(1) &\text{otherwise}
+  \end{dcases}\\
+  &= \begin{dcases}
+    2n - \Theta(1) + T(n - \Theta(1)) &\text{if }n > 0\\
+    \Theta(1) &\text{otherwise}
+  \end{dcases}\\
+  &= \Theta(1) + \sum_{k=1}^m(2k - \Theta(1))
+  = 2\sum_{k=1}^m k - \sum_{k=1}^m\Theta(1)
+  = m^2 + m - \sum_{k=1}^m\Theta(1)
+\end{align*}
+where $m$ satisfies
+\begin{multline*}
+  \exists\{f_k\mid k\in 1\,..\,m\} \subset \Theta(1),\,
+  \sum_{k=1}^m f_k(n) = n
+  \Longrightarrow \sum_{k=1}^m\Theta(1) = \Theta(n)
+  \Longrightarrow m = \Theta(n)\\
+  \Longrightarrow T(n) = \Theta\left(n^2\right) + \Theta(n) - \Theta(n)
+  = \Theta\left(n^1\right)
+\end{multline*}
+
+\subsection{Worst Case}
+If the array is reversely sorted, after each first \verb|while| (line 25),
+\verb|high| is decreased by \verb|size|; and after each second
+\verb|while| (line 32), \verb|low| is increased by \verb|size|.
+For \verb|low + size >= high|, it takes \verb|(high-low-size)/size + 1 >> 1|
+or \verb|nmemb / 2| iterations of the \verb|do|--\verb|while| loop (line 23).
+The overall complexity would then be
+\begin{align*}
+  \sum_{k=1}^{\lfloor n/2\rfloor}(n - 2k + 1 + n - 2k)
+  &= \sum_{k=1}^{\lfloor n/2\rfloor}(2n - 4k + 1)\\
+  &= n^2 + 2\left\lfloor\frac{n}{2}\right\rfloor
+  \left(\left\lfloor\frac{n}{2}\right\rfloor + 1\right)
+  + \left\lfloor\frac{n}{2}\right\rfloor\\
+  &= O\left(n^2\right)
+\end{align*}
+
+\section{Merge Sort}
+As usual, the linked list is implemented using classic Lisp's \verb|cons|-cells.
+The program is thus compiled by
+\begin{verbatim}
+cc construct.c Ex2.c -o Ex2
+\end{verbatim}
+
+To keep the implementation concise, memory safety as well as stack limit
+was not considered.
+
+It is trivial that the time complexity of \verb|merge| is $\Theta(n)$ with
+$n$ being the total length of \verb|left| and \verb|right|.  For \verb|msort|,
+the running time of the \verb|while| loop at line 27 is also $\Theta(n)$, where
+n is the length of the input \verb|list|.  The overall time complexity is
+\[T(n) = \begin{dcases}
+  \Theta(1) &\text{if }n \le 1\\
+  \Theta(n) + T\left(\left\lfloor\frac{n}{2}\right\rfloor\right)
+  + T\left(\left\lceil\frac{n}{2}\right\rceil\right) &\text{otherwise}
+\end{dcases}\]
+
+The recurrence can be stated as
+\[T(n) = 2T\left(\frac{n}{2}\right) + \Theta(n)\]
+\pagebreak
+
+By the master theorem\footnote{Let $a \ge 1$ and $b > 1$ be constants,
+and let $T(n)$ be defined on the nonnegative integers by the recurrence
+\[T(n) = aT\left(\frac{n}{b}\right) + \Theta\left(n^{\log_b a}\right)\]
+where $n/b$ is interpreted as either $\lfloor n/b\rfloor$ or $\lceil n/b\rceil$,
+then \[T(n) = \Theta\left(n^{\log_b a}\lg n\right)\]},
+\[T(n) = 2T\left(\frac{n}{2}\right) + \Theta\left(n^{\log_2 2}\right)
+= \Theta\left(n^{\log_2 2}\lg n\right) = \Theta(n\lg n)\]
+
+\section{Copying}
+This report along with the source files are licensed under a
+\href{https://creativecommons.org/licenses/by-sa/4.0/}{Creative Commons
+Attribution-ShareAlike 4.0 International License}.
+\end{document}
diff --git a/usth/ICT2.1/labwork/5/TT5.pdf b/usth/ICT2.1/labwork/5/TT5.pdf
new file mode 100644
index 0000000..1038597
--- /dev/null
+++ b/usth/ICT2.1/labwork/5/TT5.pdf
Binary files differdiff --git a/usth/ICT2.1/labwork/5/construct.c b/usth/ICT2.1/labwork/5/construct.c
new file mode 100644
index 0000000..235f900
--- /dev/null
+++ b/usth/ICT2.1/labwork/5/construct.c
@@ -0,0 +1,27 @@
+/*
+ * Lisp construct implementation.
+ * Copyright (C) 2019,  Nguyễn Gia Phong
+ * This software is licenced under a CC BY-SA 4.0 license
+ */
+
+#include <stdlib.h>
+
+#include "construct.h"
+
+construct *cons(void *first, construct *rest)
+{
+	construct *list = malloc(sizeof(construct));
+	list->car = first;
+	list->cdr = rest;
+	return list;
+}
+
+void *car(construct *list)
+{
+	return list->car;
+}
+
+construct *cdr(construct *list)
+{
+	return list->cdr;
+}
diff --git a/usth/ICT2.1/labwork/5/construct.h b/usth/ICT2.1/labwork/5/construct.h
new file mode 100644
index 0000000..a27a1c3
--- /dev/null
+++ b/usth/ICT2.1/labwork/5/construct.h
@@ -0,0 +1,15 @@
+/*
+ * Lisp construct header.
+ * Copyright (C) 2019,  Nguyễn Gia Phong
+ * This software is licenced under a CC BY-SA 4.0 license
+ */
+
+typedef struct list construct;
+struct list {
+	void *car;
+        construct *cdr;
+};
+
+construct *cons(void *, construct *);
+void *car(construct *);
+construct *cdr(construct *);