Skip to content

Commit

Permalink
Hiệu chỉnh thuật toán trên mảng - Sử dụng hàm cmp thay cho order
Browse files Browse the repository at this point in the history
  • Loading branch information
bangoc committed Jan 30, 2025
1 parent 3e8b9fc commit 1e73435
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 46 deletions.
92 changes: 66 additions & 26 deletions v3/algo.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* (C) Nguyễn Bá Ngọc 2025 */

#ifndef ALGO_H_
#define ALGO_H_

Expand All @@ -18,34 +20,34 @@ static inline void vassign(void *dest, void *src, int sz) {
}

static void insort(void *a, int n, int sz,
int (*order)(const void *, const void *)) {
int (*cmp)(const void *, const void *)) {
char v[sz];
for (int i = 1; i < n; ++i) {
void *p = a + i * sz;
vassign(v, p, sz);
p -= sz;
while (p >= a && !order(p, v)) {
while (p >= a && cmp(p, v) > 0) {
vassign(p + sz, p, sz);
p -= sz;
}
vassign(p +sz, v, sz);
vassign(p + sz, v, sz);
}
}

static void q2insort(void *a, int n, int sz,
int (*order)(const void *, const void *)) {
int (*cmp)(const void *, const void *)) {
if (n < 8) {
insort(a, n, sz, order);
insort(a, n, sz, cmp);
return;
}
void *left = a, *right = a + (n - 1) * sz,
*mid = left + ((n - 1) >> 1) * sz;
if (!order(left, mid)) {
if (cmp(left, mid) > 0) {
vswap(left, mid, sz);
}
if (!order(mid, right)) {
if (cmp(mid, right) > 0) {
vswap(mid, right, sz);
if (!order(left, mid)) {
if (cmp(left, mid) > 0) {
vswap(left, mid, sz);
}
}
Expand All @@ -54,10 +56,10 @@ static void q2insort(void *a, int n, int sz,
char v[sz];
vassign(v, mid, sz);
do {
while (!order(v, left)) {
while (cmp(left, v) < 0) {
left += sz;
}
while (!order(right, v)) {
while (cmp(v, right) < 0) {
right -= sz;
}
if (left < right) {
Expand All @@ -69,15 +71,15 @@ static void q2insort(void *a, int n, int sz,
right -= sz;
}
} while (left <= right);
q2insort(a, (right - a) / sz + 1, sz, order);
q2insort(left, n - (left - a) / sz, sz, order);
q2insort(a, (right - a) / sz + 1, sz, cmp);
q2insort(left, n - (left - a) / sz, sz, cmp);
}

static void *binsearch(void *key, void *a, int n, int sz,
int (*cmp)(const void *, const void *)) {
int l = 0, r = n - 1;
while (l <= r) {
int m = (l + r) / 2;
int m = (l + r) >> 1;
void *p = a + m * sz;
int tmp = cmp(key, p);
if (tmp == 0) {
Expand All @@ -92,18 +94,56 @@ static void *binsearch(void *key, void *a, int n, int sz,
return 0;
}

static void *binsearch_lte(void *key, void *a, int n, int sz,
int (*cmp)(const void *, const void *)) {
int l = 0, r = n - 1;
while (l <= r) {
int m = (l + r) >> 1;
void *p = a + m * sz;
int tmp = cmp(key, p);
if (tmp == 0) {
return p;
}
if (tmp > 0) {
l = m + 1;
} else {
r = m - 1;
}
}
return r < 0? 0: a + r * sz;
}

static void *binsearch_gte(void *key, void *a, int n, int sz,
int (*cmp)(const void *, const void *)) {
int l = 0, r = n - 1;
while (l <= r) {
int m = (l + r) >> 1;
void *p = a + m * sz;
int tmp = cmp(key, p);
if (tmp == 0) {
return p;
}
if (tmp > 0) {
l = m + 1;
} else {
r = m - 1;
}
}
return l >= n? 0: a + l * sz;
}

#define TOP(i) (((i) - 1) >> 1)
#define LEFT(i) (((i) << 1) + 1)
#define RIGHT(i) (((i) << 1) + 2)

static void heap_shift_down(void *a, int n, int sz, int i,
int (*order)(const void *, const void *)) {
int (*cmp)(const void *, const void *)) {
for (;;) {
int lc = LEFT(i), rc = RIGHT(i), top = i;
if (lc < n && !order(a + top * sz, a + lc * sz)) {
if (lc < n && cmp(a + top * sz, a + lc * sz) > 0) {
top = lc;
}
if (rc < n && !order(a + top * sz, a + rc * sz)) {
if (rc < n && cmp(a + top * sz, a + rc * sz) > 0) {
top = rc;
}
if (top == i) {
Expand All @@ -115,28 +155,28 @@ static void heap_shift_down(void *a, int n, int sz, int i,
}

static void heap_shift_up(void *a, int n, int sz, int i,
int (*order)(const void *, const void *)) {
int (*cmp)(const void *, const void *)) {
int top = TOP(i);
while (i > 0 && !order(a + top * sz, a + i * sz)) {
while (i > 0 && cmp(a + top * sz, a + i * sz) > 0) {
vswap(a + i * sz, a + top * sz, sz);
i = top;
top = TOP(top);
}
}

static void heapify(void *a, int n, int sz,
int (*order)(const void *, const void *)) {
int (*cmp)(const void *, const void *)) {
for (int i = TOP(n - 1); i >= 0; --i) {
heap_shift_down(a, n, sz, i, order);
heap_shift_down(a, n, sz, i, cmp);
}
}

static void heapsort(void *a, int n, int sz,
int (*order)(const void *, const void *)) {
heapify(a, n, sz, order);
int (*cmp)(const void *, const void *)) {
heapify(a, n, sz, cmp);
for (int i = n - 1; i > 0; --i) {
vswap(a, a + i * sz, sz);
heap_shift_down(a, i, sz, 0, order);
heap_shift_down(a, i, sz, 0, cmp);
}
char *i = a, *j = a + (n - 1) * sz;
while (i < j) {
Expand All @@ -146,7 +186,7 @@ static void heapsort(void *a, int n, int sz,
}
}

#define VHEAPSORT(v, order) heapsort(v->elems, v->size, sizeof(v->elems[0]), order)
#define VQ2INSORT(v, order) q2insort(v->elems, v->size, sizeof(v->elems[0]), order)
#define VHEAPSORT(v, cmp) heapsort(v->elems, v->size, sizeof(v->elems[0]), cmp)
#define VQ2INSORT(v, cmp) q2insort(v->elems, v->size, sizeof(v->elems[0]), cmp)

#endif // ALGO_H_
#endif // ALGO_H_
2 changes: 2 additions & 0 deletions v3/dlist.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* (C) Nguyễn Bá Ngọc 2025 */

#ifndef DLIST_H_
#define DLIST_H_

Expand Down
30 changes: 30 additions & 0 deletions v3/tests/binsearch_ut.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,34 @@ int main() {
binsearch((int[]){-10}, a, n, sizeof(int), icmp) != 0) {
return 1;
}
int *tmp = binsearch_lte((int[]){7}, a, n, sizeof(int), icmp);
if (*tmp != 6) {
printf("%d - error\n", *tmp);
return 1;
}
tmp = binsearch_gte((int[]){7}, a, n, sizeof(int), icmp);
if (*tmp != 8) {
printf("%d - error\n", *tmp);
return 1;
}
tmp = binsearch_lte((int[]){0}, a, n, sizeof(int), icmp);
if (tmp) {
printf("Error lte\n");
return 1;
}
tmp = binsearch_gte((int[]){11}, a, n, sizeof(int), icmp);
if (tmp) {
printf("Error gte\n");
return 1;
}
tmp = binsearch_lte((int[]){11}, a, n, sizeof(int), icmp);
if (*tmp != 10) {
printf("%d - error\n", *tmp);
return 1;
}
tmp = binsearch_gte((int[]){0}, a, n, sizeof(int), icmp);
if (*tmp != 1) {
printf("%d - error\n", *tmp);
return 1;
}
}
2 changes: 2 additions & 0 deletions v3/tests/dlist_demo_ut.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* (C) Nguyễn Bá Ngọc 2025 */

#include "dlist.h"

#include <stdio.h>
Expand Down
16 changes: 8 additions & 8 deletions v3/tests/heap_sort_ut.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,30 @@

#include <stdio.h>

int lte(const void *o1, const void *o2) {
int icmp(const void *o1, const void *o2) {
const int *v1 = o1, *v2 = o2;
return *v1 <= *v2;
return *v1 - *v2;
}

int gte(const void *o1, const void *o2) {
int icmpr(const void *o1, const void *o2) {
const int *v1 = o1, *v2 = o2;
return *v1 >= *v2;
return *v2 - *v1;
}

int main() {
int a[] = {3, 1, 2};
int n = sizeof(a) / sizeof(a[0]);
heapsort(a, n, sizeof(int), lte);
heapsort(a, n, sizeof(int), icmp);
for (int i = 0; i < n; ++i) {
if (i > 0 && !lte(a + (i - 1), a + i)) {
if (i > 0 && icmp(a + (i - 1), a + i) > 0) {
return 1;
}
printf("%d ", a[i]);
}
printf("\n");
heapsort(a, n, sizeof(int), gte);
heapsort(a, n, sizeof(int), icmpr);
for (int i = 0; i < n; ++i) {
if (i > 0 && !gte(a + (i - 1), a + i)) {
if (i > 0 && icmpr(a + (i - 1), a + i) > 0) {
return 1;
}
printf("%d ", a[i]);
Expand Down
8 changes: 4 additions & 4 deletions v3/tests/ivec_sort_ut.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

VECT_DECL_IMPL(ivec, int)

int lte(const void *o1, const void *o2) {
return *((const int *)o1) <= *((const int *)o2);
int icmp(const void *o1, const void *o2) {
return *((const int *)o1) - *((const int *)o2);
}

int main() {
Expand All @@ -17,9 +17,9 @@ int main() {
for (int i = 0; i < 10; ++i) {
ivec_append(v, rand());
}
VQ2INSORT(v, lte);
VQ2INSORT(v, icmp);
for (int i = 0; i < v->size; ++i) {
if (i > 0 && !lte(v->elems + i - 1, v->elems + i)) {
if (i > 0 && icmp(v->elems + i - 1, v->elems + i) > 0) {
return 1;
}
}
Expand Down
24 changes: 16 additions & 8 deletions v3/tests/q2insort_ut.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,41 @@

#include <stdio.h>

int lte(const void *o1, const void *o2) {
int icmp(const void *o1, const void *o2) {
const int *v1 = o1, *v2 = o2;
return *v1 <= *v2;
return *v1 - *v2;
}

int gte(const void *o1, const void *o2) {
int icmpr(const void *o1, const void *o2) {
const int *v1 = o1, *v2 = o2;
return *v1 >= *v2;
return *v2 - *v1;
}

int main() {
int a[] = {3, 1, 2, 9, 3, 2, 7, 10, 21, 22, 35, 21, 1, 3, 2};
int n = sizeof(a) / sizeof(a[0]);
q2insort(a, n, sizeof(int), lte);
q2insort(a, n, sizeof(int), icmp);
for (int i = 0; i < n; ++i) {
if (i > 0 && !lte(a + (i - 1), a + i)) {
if (i > 0 && icmp(a + (i - 1), a + i) > 0) {
return 1;
}
printf("%d ", a[i]);
}
printf("\n");
q2insort(a, n, sizeof(int), gte);
q2insort(a, n, sizeof(int), icmpr);
for (int i = 0; i < n; ++i) {
if (i > 0 && !gte(a + (i - 1), a + i)) {
if (i > 0 && icmpr(a + (i - 1), a + i) > 0) {
return 1;
}
printf("%d ", a[i]);
}
printf("\n");
int b[10] = {0};
int bn = sizeof(b) / sizeof(b[0]);
q2insort(b, bn, sizeof(int), icmp);
q2insort(b, bn, sizeof(int), icmpr);
for (int i = 0; i < bn; ++i) {
printf("%d ", b[i]);
}
printf("\n");
}

0 comments on commit 1e73435

Please sign in to comment.