我将输入作为数组A = [ 2,3,4,1]
输出只是A中元素的所有可能排列,可以通过单个转置(单个翻转两个相邻元素)操作来完成。所以输出是:
[3,2,4,1],[ 2,4,3,1],[2,3,1,4],[1,3,4,2]
允许圆形转置。因此[2,3,4,1]
==>允许[1,3,4,2]
和有效输出。
如何在C中执行此操作?
修改 在python中,它将按如下方式完成:
def Transpose(alist):
leveloutput = []
n = len(alist)
for i in range(n):
x=alist[:]
x[i],x[(i+1)%n] = x[(i+1)%n],x[i]
leveloutput.append(x)
return leveloutput
答案 0 :(得分:2)
此解决方案使用动态内存分配,这样您就可以为大小为size
的数组执行此操作。
int *swapvalues(const int *const array, size_t size, int left, int right)
{
int *output;
int sotred;
output = malloc(size * sizeof(int));
if (output == NULL) /* check for success */
return NULL;
/* copy the original values into the new array */
memcpy(output, array, size * sizeof(int));
/* swap the requested values */
sotred = output[left];
output[left] = output[right];
output[right] = sotred;
return output;
}
int **transpose(const int *const array, size_t size)
{
int **output;
int i;
int j;
/* generate a swapped copy of the array. */
output = malloc(size * sizeof(int *));
if (output == NULL) /* check success */
return NULL;
j = 0;
for (i = 0 ; i < size - 1 ; ++i)
{
/* allocate space for `size` ints */
output[i] = swapvalues(array, size, j, 1 + j);
if (output[i] == NULL)
goto cleanup;
/* in the next iteration swap the next two values */
j += 1;
}
/* do the same to the first and last element now */
output[i] = swapvalues(array, size, 0, size - 1);
if (output[i] == NULL)
goto cleanup;
return output;
cleanup: /* some malloc call returned NULL, clean up and exit. */
if (output == NULL)
return NULL;
for (j = i ; j >= 0 ; j--)
free(output[j]);
free(output);
return NULL;
}
int main()
{
int array[4] = {2, 3, 4, 1};
int i;
int **permutations = transpose(array, sizeof(array) / sizeof(array[0]));
if (permutations != NULL)
{
for (i = 0 ; i < 4 ; ++i)
{
int j;
fprintf(stderr, "[ ");
for (j = 0 ; j < 4 ; ++j)
{
fprintf(stderr, "%d ", permutations[i][j]);
}
fprintf(stderr, "] ");
free(permutations[i]);
}
fprintf(stderr, "\n");
}
free(permutations);
return 0;
}
虽然有些人认为goto
是邪恶的,但这对它来说非常好用,不能用它来控制程序的流程(例如创建循环),这令人困惑。但是对于在返回之前必须做几件事的功能的退出点,它认为它实际上是一个很好的用途,它是我的看法,对我来说它使代码更容易理解,我可能是错。
答案 1 :(得分:1)
看看我用一个例子写的代码:
void transpose() {
int arr[] = {3, 5, 8, 1};
int l = sizeof (arr) / sizeof (arr[0]);
int i, j, k;
for (i = 0; i < l; i++) {
j = (i + 1) % l;
int copy[l];
for (k = 0; k < l; k++)
copy[k] = arr[k];
int t = copy[i];
copy[i] = copy[j];
copy[j] = t;
printf("{%d, %d, %d, %d}\n", copy[0], copy[1], copy[2], copy[3]);
}
}
示例输出:
{5, 3, 8, 1}
{3, 8, 5, 1}
{3, 5, 1, 8}
{1, 5, 8, 3}
答案 2 :(得分:1)
一些注意事项:
单个内存块比指针数组更受欢迎,因为它具有更好的局部性和更少的堆碎片;
循环转置只有一个,它可以单独完成,从而避免了每次迭代中模运算符的开销。
以下是代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int *single_transposition(const int *a, unsigned int n) {
// Output size is known, can use a single allocation
int *out = malloc(n * n * sizeof(int));
// Perform the non-cyclic transpositions
int *dst = out;
for (int i = 0; i < n - 1; ++i) {
memcpy(dst, a, n * sizeof (int));
int t = dst[i];
dst[i] = dst[i + 1];
dst[i + 1] = t;
dst += n;
}
// Perform the cyclic transposition, no need to impose the overhead
// of the modulo operation in each of the above iterations.
memcpy(dst, a, n * sizeof (int));
int t = dst[0];
dst[0] = dst[n-1];
dst[n-1] = t;
return out;
}
int main() {include
int a[] = { 2, 3, 4, 1 };
const unsigned int n = sizeof a / sizeof a[0];
int *b = single_transposition(a, n);
for (int i = 0; i < n * n; ++i)
printf("%d%c", b[i], (i % n) == n - 1 ? '\n' : ' ');
free(b);
}
答案 3 :(得分:0)
有很多方法可以解决这个问题,最重要的问题是:如何使用输出以及变量是数组的大小。你已经说过阵列会非常大,因此我假设内存,而不是CPU将是这里最大的瓶颈。
如果输出仅使用几次(特别是只使用一次),最好使用功能方法:动态生成每个转置,并且一次不要在内存中使用多个转置。对于这种方法,许多高级语言可以起作用(有时甚至可能比C更好)。
如果数组的大小是固定的或半固定的(例如在编译时已知的几个大小),您可以使用C ++模板定义结构。
如果size是动态的并且你仍然希望在内存中进行每个转置,那么你应该分配一个巨大的内存块并将其视为连续的数组数组。这在机器级别上非常简单明了。不幸的是,它最好使用指针算法来解决,这是C / C ++的一个以难以理解而闻名的特性。 (如果你从基础知识中学习C,那就不是了,但是从高级语言中跳出来的人已经证明了第一次完全错误的记录) 其他方法是使用大数组指向较小数组的指针,这会产生双指针,这对新手来说更加可怕。
很抱歉这篇文章并不是真正的答案,但恕我直言,选择最佳解决方案的问题太多了,我觉得你需要更多的C基础知识才能自己管理它们。
/编辑: 由于已经发布了其他解决方案,因此这是一个内存占用最少的解决方案。这是最有限的方法,它反复使用相同的一个缓冲区,你必须确保你的代码完成第一个转置,然后再转到下一个。从好的方面来说,当其他解决方案需要太字节的内存时,它仍然会正常工作。它也是如此苛刻,以至于它可以用高级语言实现。我坚持使用C ++,以防你想一次拥有多个矩阵(例如比较它们或同时运行多个线程)。
#define NO_TRANSPOSITION -1
class Transposable1dMatrix
{
private:
int * m_pMatrix;
int m_iMatrixSize;
int m_iCurrTransposition;
//transposition N means that elements N and N+1 are swapped
//transpostion -1 means no transposition
//transposition (size-1) means cyclic transpostion
//as usual in C (size-1) is the last valid index
public:
Transposable1dMatrix(int MatrixSize)
{
m_iMatrixSize = MatrixSize;
m_pMatrix = new int[m_iMatrixSize];
m_iCurrTransposition = NO_TRANSPOSITION;
}
int* GetCurrentMatrix()
{
return m_pMatrix;
}
bool IsTransposed()
{
return m_iCurrTransposition != NO_TRANSPOSITION;
}
void ReturnToOriginal()
{
if(!IsTransposed())//already in original state, nothing to do here
return;
//apply same transpostion again to go back to original
TransposeInternal(m_iCurrTransposition);
m_iCurrTransposition = NO_TRANSPOSITION;
}
void TransposeTo(int TranspositionIndex)
{
if(IsTransposed())
ReturnToOriginal();
TransposeInternal(TranspositionIndex);
m_iCurrTransposition = TranspositionIndex;
}
private:
void TransposeInternal(int TranspositionIndex)
{
int Swap1 = TranspositionIndex;
int Swap2 = TranspositionIndex+1;
if(Swap2 == m_iMatrixSize)
Swap2 = 0;//this is the cyclic one
int tmp = m_pMatrix[Swap1];
m_pMatrix[Swap1] = m_pMatrix[Swap2];
m_pMatrix[Swap2] = tmp;
}
};
void main(void)
{
int arr[] = {2, 3, 4, 1};
int size = 4;
//allocate
Transposable1dMatrix* test = new Transposable1dMatrix(size);
//fill data
memcpy(test->GetCurrentMatrix(), arr, size * sizeof (int));
//run test
for(int x = 0; x<size;x++)
{
test->TransposeTo(x);
int* copy = test->GetCurrentMatrix();
printf("{%d, %d, %d, %d}\n", copy[0], copy[1], copy[2], copy[3]);
}
}