如何“排序和修改”一个列表?

huangapple go评论62阅读模式
英文:

How to "sort and modify" a list?

问题

我不确定这个主题是否已经被讨论过,但如果是这样,我没有正确的关键词来找到它。在我的代码中,我提取一个映射,就像这样:{5,0,23,2,2,0}。如你所见,这些值不是连续的。我想要做的是将这个映射转换为返回的列表是{3,0,4,1,2,0}。这里的0表示元素应该被忽略。所以基本上我想做的是根据它们的顺序重新编号这些元素,而不是移动它们在列表中的位置。

我通过首先创建我的初始数组的副本,然后使用stdlib C库中的qsort对这个副本进行排序来实现这个目标。我还创建了一个return_list,其中将存储我的最终映射。

(初始数组是vec)

elt_count = 1;
for (size_t i = 0; i < n; i++) {
    if (copy[i] != 0) {
        for (size_t j = 0; j < n; j++) {
            if (copy[i] == vec[j]) {
                return_list[j] = elt_count;
                vec[j] = 0;
                elt_count++;
                break;
            }
        }
    }
}

在这里,我使用一个计数器为最终映射赋予它的值。

问题是,我的方法中的这部分需要很多时间,而且减慢了我的整个程序,而我本应该使用映射来节省时间。

我认为我可以像这样存储每个元素的位置来尝试提高性能:

vec = (5,0,23,2,2,0)
5: (0)
23: (2)
2: (3,4)

然而,我不确定如何实施这个并且如何使用它来提高性能。

当然,欢迎任何其他改进性能的想法!

英文:

I am not sure if this subject was already treated but if it's the case I did not have the right keyword to find it.
In my code I extract a mapping so let's say: {5,0,23,2,2,0}. As you can see the values are not contiguous. What I would like to do is transform this mapping so that the returned list is {3,0,4,1,2,0}. Here 0 means that the element should be ignored. So basically what I want to do is renumber the elements based on their order without moving them in the list.

I did that by first creating a copy of my initial array and then sorting this copy using qsort from the stdlib C library. I also created a return_list in which my final mapping will be stored.

(the initial array is vec)

    elt_count = 1;
    for (size_t i = 0; i &lt; n; i++) {
        if (copy[i] != 0) {
            for (size_t j = 0; j &lt; n; j++) {
                if (copy[i] == vec[j]) {
                    return_list[j] = elt_count;
                    vec[j] = 0;
                    elt_count++;
                    break;
                }
            }
        }
    }

Here I use a counter to give the final mapping its values.

The problem is that this part of my method takes a lot of time and slows down my whole program while I was supposed to use the mapping to gain time.

I think I could store the position of each elements like this to try and improve the performances:

vec = (5,0,23,2,2,0)
5: (0)
23: (2)
2: (3,4)

However I am not sure how to implement this and then use it to gain performance.

Of course any other ideas to improve the performances are welcome !

答案1

得分: 2

以下是您要翻译的内容:

一种简单的方法是创建一个包含值的索引的数组副本:

    int a2[n][2];
    int zeros = 0;
    for (int i = 0; i < n; i++) {
        a2[i - zeros][0] = vec[i];
        a2[i - zeros][1] = i;
        zeros += (vec[i] == 0);
    }

现在 `a2` 是一个长度为 `n-zeros` 的数组,其条目是 `vec` 的非零元素与它们的索引配对。

现在对 `a2` 进行排序:

    qsort(a2, n - zeros, sizeof(a2[0]), cmp_a2);

使用这个比较函数:

    int cmp_a2(const void *v, const void *w) {
        const int *a = v;
        const int *b = w;
        if (a[0] < b[0]) return -1;
        if (a[0] > b[0]) return 1;
        if (a[1] < b[1]) return -1;
        if (a[1] > b[1]) return 1;
        return 0;
    }

现在,您可以使用排序后的 `a2` 中存储的原始索引替换数组中的原始元素:

    for (int i = 0; i < n - zeros; i++) {
        vec[a2[i][1]] = i + 1;
    }

这里是所有部分完整的工作示例:

    #include <stdlib.h>
    #include <stdio.h>
    
    void print_array(int *a, size_t n) {
    	for (int i = 0; i < n; i++)
    		printf("%s%d", i > 0 ? ", " : "", a[i]);
    	printf("\n");
    }
    
    int cmp_a2(const void *v, const void *w) {
        const int *a = v;
        const int *b = w;
        if (a[0] < b[0]) return -1;
        if (a[0] > b[0]) return 1;
        if (a[1] < b[1]) return -1;
        if (a[1] > b[1]) return 1;
        return 0;
    }
    
    void order_array(int *vec, size_t n) {
    	int (*a2)[2] = malloc(n * 2 * sizeof(int));
        size_t zeros = 0;
        for (int i = 0; i < n; i++) {
            a2[i - zeros][0] = vec[i];
            a2[i - zeros][1] = i;
            zeros += (vec[i] == 0);
        }
        qsort(a2, n - zeros, sizeof(a2[0]), cmp_a2);
    
        for (int i = 0; i < n - zeros; i++) {
            vec[a2[i][1]] = i + 1;
        }
        free(a2);
    }
    
    int main(int argc, char *argv[]) {
    	int a[] = {5,0,23,2,2,0};
    	size_t n = sizeof(a) / sizeof(*a);
    	print_array(a, n);
    	order_array(a, n);
    	print_array(a, n);
    }

请注意,这段代码将数组 a 中的元素重新排序,将非零元素替换为它们在重新排序后的数组中的索引。

英文:

One easy approach is to make a copy of your array including the indexes of the values:

int a2[n][2];
int zeros = 0;
for (int i = 0; i &lt; n; i++) {
a2[i - zeros][0] = vec[i];
a2[i - zeros][1] = i;
zeros += (vec[i] == 0);
}

Now a2 is an array of length n-zeros, and its entries are the non-zero elements of vec paired with their indexes.

Now sort a2:

qsort(a2, n - zeros, sizeof(a2[0]), cmp_a2);

Using this comparison function:

int cmp_a2(const void *v, const void*w) {
const int *a = v;
const int *b = w;
if (a[0] &lt; b[0]) return -1;
if (a[0] &gt; b[0]) return 1;
if (a[1] &lt; b[1]) return -1;
if (a[1] &gt; b[1]) return 1;
return 0;
}

Now you can replace the original elements in the array, using the original indices stored in the sorted a2:

for (int i = 0; i &lt; n - zeros; i++) {
vec[a2[i][1]] = i + 1;
}

Here's all the pieces together as complete working example:

#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
void print_array(int *a, size_t n) {
for (int i = 0; i &lt; n; i++)
printf(&quot;%s%d&quot;, i&gt;0 ? &quot;, &quot; : &quot;&quot;, a[i]);
printf(&quot;\n&quot;);
}
int cmp_a2(const void *v, const void*w) {
const int *a = v;
const int *b = w;
if (a[0] &lt; b[0]) return -1;
if (a[0] &gt; b[0]) return 1;
if (a[1] &lt; b[1]) return -1;
if (a[1] &gt; b[1]) return 1;
return 0;
}
void order_array(int *vec, size_t n) {
int (*a2)[2] = malloc(n * 2 * sizeof(int));
size_t zeros = 0;
for (int i = 0; i &lt; n; i++) {
a2[i - zeros][0] = vec[i];
a2[i - zeros][1] = i;
zeros += (vec[i] == 0);
}
qsort(a2, n - zeros, sizeof(a2[0]), cmp_a2);
for (int i = 0; i &lt; n - zeros; i++) {
vec[a2[i][1]] = i + 1;
}
free(a2);
}
int main(int argc, char *argv[]) {
int a[] = {5,0,23,2,2,0};
size_t n = sizeof(a) / sizeof(*a);
print_array(a, n);
order_array(a, n);
print_array(a, n);
}

答案2

得分: -1

你可以使用标准库函数 qsortbsearch 来解决这个问题。以下是一个开始:

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])

int ElemDiff(const void *leftElemPtr, const void *rightElemPtr) {
    return *(int *) leftElemPtr - *(int *) rightElemPtr;
}

int main(void)
{
    int vec[] = {5, 0, 23, 2, 2, 0};
    int sortedVec[LEN(vec)];
    int i, *tail;

    memcpy(sortedVec, vec, sizeof (vec));
    qsort(sortedVec, LEN(sortedVec), sizeof sortedVec[0], ElemDiff);
    for (i = 0; i < LEN(vec); i++) {
        tail = bsearch(vec + i, sortedVec, LEN(sortedVec), sizeof sortedVec[0], ElemDiff);
        assert(tail != NULL);
        printf("%lld ", tail - sortedVec);
    }
    putchar('\n');

    return 0;
}

这会打印:

4 0 5 2 2 0
英文:

You can use the the standard library functions qsort and bsearch to solve the problem. Here is a start:

#include &lt;assert.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])
int ElemDiff(const void *leftElemPtr, const void *rightElemPtr) {
return *(int *) leftElemPtr - *(int *) rightElemPtr;
}
int main(void)
{
int vec[] = {5, 0, 23, 2, 2, 0};
int sortedVec[LEN(vec)];
int i, *tail;
memcpy(sortedVec, vec, sizeof (vec));
qsort(sortedVec, LEN(sortedVec), sizeof sortedVec[0], ElemDiff);
for (i = 0; i &lt; LEN(vec); i++) {
tail = bsearch(vec + i, sortedVec, LEN(sortedVec), sizeof sortedVec[0], ElemDiff);
assert(tail != NULL);
printf(&quot;%lld &quot;, tail - sortedVec);
}
putchar(&#39;\n&#39;);
return 0;
}

This will print

4 0 5 2 2 0

huangapple
  • 本文由 发表于 2023年4月4日 16:00:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/75926871.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定