我正在学习C并且讨论了排序问题。我写了一个comp()
函数并使用qsort
对int
数组进行排序。现在我需要从下一个任务中删除数组中的重复项
是否可以同时对重复项进行排序和删除?
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int indexes[10] = { 0, 98, 45, 65, 45, 98, 78, 56, 65, 45 };
int comp(const void * elem1, const void * elem2) {
int f = *((int*) elem1);
int s = *((int*) elem2);
if (f > s) {
return 1;
}
if (f < s) {
return -1;
}
return 0;
}
void printIndexArray() {
int i = 0;
for (i = 0; i < 10; i++) {
printf("i is %d\n", indexes[i]);
}
}
int main() {
qsort(indexes, sizeof(indexes) / sizeof(int), sizeof(int), comp);
printIndexArray();
return 0;
}
答案 0 :(得分:2)
由于您的号码已经排序,因此删除欺骗很容易。在C ++中,它甚至内置为std::unique
:
http://en.cppreference.com/w/cpp/algorithm/unique
假设你想自己做,你可以像unique
那样做:
int* unique (int* first, int* last)
{
if (first==last) return last;
int* result = first;
while (++first != last)
{
if (!(*result == *first))
*(++result)=*first;
}
return ++result;
}
答案 1 :(得分:1)
是
这可以通过mergesort来实现。如果左右两者相同,则只合并一个值
答案 2 :(得分:1)
这是使用mergesort删除重复项的代码。这段代码执行删除工作:
else if(a[p1] == a[p2])
{
merged[p] = a[p1];
p1++;
p2++;
}
这是迭代合并排序,而递归版本会更容易。
#include <stdio.h>
#include <stdlib.h>
#define min(a,b) (((a) < (b)) ? (a) : (b))
int indexes[10] = { 0, 98, 45, 65, 45, 98, 78, 56, 65, 45 };
void merge(int *a, int s, int m, int e)
{
int p1 = s;
int p2 = m + 1;
int * merged = (int*)malloc(sizeof(int) * (e - s + 1));
int p = 0;
while(p1 < m + 1 && p2 < e + 1)
{
if(a[p1] > a[p2])
{
merged[p] = a[p2];
p2++;
}
else if(a[p1] == a[p2])
{
merged[p] = a[p1];
p1++;
p2++;
}
else
{
merged[p] = a[p1];
p1++;
}
p++;
}
while(p1 < m + 1)
{
merged[p++] = a[p1++];
}
while(p2 < e + 1)
merged[p++] = a[p2++];
int i;
for(i = 0;i < (e -s+1); i++)
{
a[s + i] = merged[i];
}
free(merged);
}
void merge_sort(int *a, int n)
{
int width;
for(width = 1; width < n; width = 2 * width)
{
int i;
for(i = 0; i < n; i = i + 2 * width)
{
merge(a, i, min(i + width - 1, n - 1), min(i + 2 * width - 1, n - 1) );
}
}
}
void printIndexArray()
{
int i = 0;
for(i = 0; i < 10; i++)
{
printf("i is %d\n", indexes[i]);
}
}
int main()
{
merge_sort(indexes, sizeof(indexes) / sizeof(int) );
printIndexArray();
return 0;
}
答案 3 :(得分:0)
简短的回答是:是的。
答案很长:它始终是可能的,但这样做的复杂性在很大程度上取决于您使用的算法。
更复杂的算法,如快速排序,慢速排序,桶排序和直接基数排序,不适合这种增强,因为它们依赖于连续数组中的数据,这可能是隐含的被分成子阵列。因此,当您检测到重复时,您无法轻易将其取出。同样,这对初学者来说是可能的,但肯定不是问题。
不太复杂的就地算法(如冒泡排序,插入排序和shell排序)使它相对容易:您可以使用比所有合法值排序更大的标记值替换您检测到的重复项之一,让它升到顶峰。在那之后,你只需要舀掉哨兵价值,你就完成了。
真正有助于删除重复项的算法是那些使用在过程中增长/缩小的中间数组的算法;在这些情况下,当您检测到重复时,您可以缩小或跳过增长其中一个中间数组。候选人是合并排序和堆排序。
但是,请注意,对数组进行排序更为谨慎,并在第二个单独的步骤中消除重复项。为什么?因为消除重复会增加排序算法的内部循环的复杂性,在大多数相关情况下,这是O(n * log(n))。但是从排序数组中删除重复是O(n)操作,使得拆分操作比融合操作更快。
答案 4 :(得分:0)
#include <stdio.h>
#include <stdlib.h>
int indexes[10] = { 0, 98, 45, 65, 45, 98, 78, 56, 65, 45 };
size_t undup(int array[], size_t len)
{
size_t src,dst;
if (!len) return 0;
for (src=dst=1; src < len; src++) {
if (array[dst-1] == array[src]) continue;
array[dst++] = array[src];
}
return dst;
}
int comp(const void * elem1, const void * elem2) {
int f = *((int*) elem1);
int s = *((int*) elem2);
if (f > s) return 1;
if (f < s) return -1;
return 0;
}
void printIndexArray(size_t len) {
size_t i = 0;
for (i = 0; i < len; i++) {
printf("array[%zu] is %d\n", i, indexes[i]);
}
}
int main() {
size_t len = 10;
printf("Before sort\n" );
printIndexArray(len);
qsort(indexes, sizeof indexes / sizeof indexes[0], sizeof indexes[0], comp);
printf("After sort\n" );
printIndexArray(len);
len = undup(indexes,10);
printf("After undup\n" );
printIndexArray(len);
return 0;
}