permutation.c 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /* GNU LGPL version 2 (or later) - see LICENSE file for details */
  2. #include "config.h"
  3. #include <assert.h>
  4. #include <ccan/build_assert/build_assert.h>
  5. #include <ccan/mem/mem.h>
  6. #include <ccan/permutation/permutation.h>
  7. unsigned long long permutation_count(int n)
  8. {
  9. unsigned long long count = 1;
  10. int i;
  11. for (i = 1; i <=n; i++)
  12. count *= i;
  13. return count;
  14. }
  15. struct plain_change_state {
  16. int8_t dir : 2;
  17. uint8_t pos : PERMUTATION_MAX_SHIFT;
  18. };
  19. static inline struct plain_change_state *get_state(struct permutation *pi)
  20. {
  21. BUILD_ASSERT(sizeof(struct plain_change_state) == 1);
  22. return (struct plain_change_state *)(pi + 1) + pi->n;
  23. }
  24. struct permutation *permutation_new(int n)
  25. {
  26. struct permutation *pi;
  27. int i;
  28. struct plain_change_state *xs;
  29. assert(n <= PERMUTATION_MAX_ITEMS);
  30. pi = malloc(sizeof(*pi) + 2 * n);
  31. if (!pi)
  32. return NULL;
  33. pi->n = n;
  34. xs = get_state(pi);
  35. for (i = 0; i < pi->n; i++) {
  36. pi->v[i] = i;
  37. xs[i].pos = i;
  38. xs[i].dir = (i == 0) ? 0 : -1;
  39. }
  40. return pi;
  41. }
  42. permutation_swap_t permutation_change(struct permutation *pi)
  43. {
  44. int v, w, i;
  45. int a, b, vdir;
  46. struct plain_change_state *xs = get_state(pi);
  47. if (!pi->n)
  48. return 0;
  49. for (v = pi->n - 1; v > 0; v--) {
  50. if (xs[v].dir)
  51. break;
  52. }
  53. a = xs[v].pos;
  54. vdir = xs[v].dir;
  55. if (!vdir)
  56. return 0;
  57. b = a + vdir;
  58. w = pi->v[b];
  59. pi->v[a] = w;
  60. pi->v[b] = v;
  61. xs[v].pos = b;
  62. xs[w].pos = a;
  63. /* If we reach the end, or the next item is larger, set
  64. * direction to 0 */
  65. if ((b == 0) || (b == (pi->n-1))
  66. || (pi->v[b + vdir] > v))
  67. xs[v].dir = 0;
  68. /* Reset direction on all elements greater than the chosen one */
  69. for (i = v + 1; i < pi->n; i++) {
  70. if (xs[i].pos < b)
  71. xs[i].dir = 1;
  72. else
  73. xs[i].dir = -1;
  74. }
  75. return (b * PERMUTATION_MAX_ITEMS) + a;
  76. }