【问题标题】:Need to check if array is sorted using a function in C需要检查数组是否使用 C 中的函数排序
【发布时间】:2022-01-02 08:50:12
【问题描述】:

基本上,我们需要检查一维数组的元素是否使用函数排序: 如果它们按升序排序:返回 1 如果它们按降序排序:返回 -1 如果它们没有排序:返回 0 这是我正在使用的方法,但是它不返回 1 而是返回 0,我不确定问题出在哪里,欢迎任何 cmet 或解决问题的新方法,因为我是初学者。

int Is_Sorted(int* A, int n){
    int tempcr, tempdcr;

for (int i=0; i<N-1; i++){

    if (A[i]<=A[i+1]){
        tempcr++;
    }else if (A[i]>=A[i+1]){
    tempdcr++;
    }
}
   if(tempcr==N-1){
        return 1;
   }else if(tempdcr==N-1)
        return -1;
   else
    return 0;

}

【问题讨论】:

  • tempcrtemdcr 未初始化。意味着它们可以包含任何垃圾值。
  • 非常感谢。有没有更好的方法来解决这个问题?
  • 如果所有项目都具有相同的值,结果应该是什么?或者如果数组只包含一个值?
  • Pung,注意Is_Sorted(int* A, int n)中的n没有在函数中使用。
  • @kaylum 有趣的micro-optimization。考虑如果数组通常接近升序/降序,那么您建议的额外检查会减慢比较速度。 IMO,一种优化将检查端点。如果它们不同,则只需要一个订单测试。 IAC,这些想法都是 O(n) 复杂度,不会减少 O()。

标签: arrays c algorithm sorting


【解决方案1】:

错误的逻辑

OP 的代码由于

而失败
}else if (A[i]>=A[i+1]){
tempdcr++;

应该是

}
if (A[i]>=A[i+1]) {
  tempdcr++;

考虑A[i]==A[i+1] 的情况,两个计数器都应该递增。

垃圾值

缺少初始化@kaylum

// int tempcr, tempdcr;
int tempcr = 0;
int tempdcr = 0;

替代方法:

有四种可能

  • 数组在每个位置 - 或长度为 0 处都有相同的值。

  • 数组正在升序。 A[i] &gt;= A[i-1] 代表所有 i &gt; 0 并且长度大于 0。

  • 数组正在下降。 A[i] &lt;= A[i-1] 代表所有 i &gt; 0 并且长度大于 0。

  • 以上都不是。

只需循环并调整两个标志。 int tempcr, tempdcr; 不需要计数器。

int Is_Sorted(const int* A, int n) {
  bool isAscending = true;
  bool isDescending = true;
  for (int i = 1; i<n; i++) { // start at 1
     if (A[i] < A[i-1]) isAscending = false;
     if (A[i] > A[i-1]) isDescending = false;
  }
  if (isAscending && isDescending) {
    return TBD; // Unsure what OP wants here
  }
  if (isAscending) {
    return 1;
  }
  if (isDescending) {
    return -1;
  }
  return 0;
}

可能会进行一些简化和一些微优化,但需要澄清一个清晰的方法。


太有趣了。

如果int a[]不是常数,我们每次迭代只能使用1个测试而不是3个:test iis lessis more em> 以上代码。

首先从头到尾寻找不等式。第一个元素被调整为与最后一个元素不同。

如果我们遍历整个列表,我们就完成了,否则列表的第一部分与最后一个元素不同。

如果最后一个比较是升序,则将第一个元素设置为 INT_MAX 并朝开头搜索非升序对。

否则
如果最后一个比较是降序的,则将第一个元素设置为 INT_MIN 并在开头搜索非降序对。

发现发生比较失败时,要么数组无序,要么我们处于开头。如果在开头,则处理该特殊情况。

在任何情况下,每次迭代只有 1 个比较。

#define ASCENDING 1
#define DESCENDING -1
#define UNORDERED 0
#define ALLSAME 1 // Adjust as desired
#define SHORT_LENGTH 1 // Adjust as desired

int is_sorted(size_t n, int *a) {
  if (n <= 1) {
    return n ? ALLSAME : SHORT_LENGTH;
  }

  int last = a[--n];
  int first = a[0];
  a[0] = !last;
  while (last == a[--n]) {
    ;
  }
  a[0] = first; // restore
  if (n == 0) {
    if (a[0] < a[1]) {
      return ASCENDING;
    }
    if (a[0] > a[1]) {
      return DESCENDING;
    }
    return ALLSAME;
  }

  if (a[n - 1] < a[n]) {
    // Only ascending, unordered possible
    a[0] = INT_MAX;
    while (a[n - 1] <= a[n]) {
      n--;
    }
    a[0] = first; // restore
    if (a[n - 1] <= a[n]) {
      return ASCENDING;
    }
  } else {
    // Only descending, unordered possible
    a[0] = INT_MIN;
    while (a[n - 1] <= a[n]) {
      n--;
    }
    a[0] = first; // restore
    if (a[n - 1] <= a[n]) {
      return DESCENDING;
    }
  }
  return UNORDERED;
}

稍后我会进行更多测试。

如果数组是const,每个循环需要2次测试。

【讨论】:

  • 你可以跳出for循环一次(如果)两个标志都变成false
  • @500-InternalServerError 是的,但这不是某种优化,因为它还会在进行更多检查时减慢运行时间。取决于典型的数组集。 IAC,它不会减少 O()。更多here.
  • @500-InternalServerError 为了好玩,在每个比较步骤中对数组进行二等分并检查端点直到大小为 1 可能会很有趣。在最坏的情况下肯定会更慢,但可能会捕获早期的无序数组并允许单序比较和/或结束早期代码。
  • 对于大型数组,或者如果代码被泛化为匹配qsort()bsearch(),提前中断可能有利于性能——它避免了潜在的许多函数调用。当数据类型为int时,比较的开销要小得多,所以早期的break vs extra testing不是那么明确。
  • @500-InternalServerError 所以我很开心每个循环只使用 1 个比较。
【解决方案2】:

对于初学者来说,函数应该像这样声明

int Is_Sorted( const int* A, size_t n );

至少第一个参数应该有限定符const,因为传递的数组在函数内没有改变。

变量tempcrtempdcr 未初始化并且具有不确定的值。因此该函数具有未定义的行为。你必须像这样初始化它们

int tempcr = 0, tempdcr = 0;

如果已经知道数组是未排序的,那么继续循环的迭代是没有意义的,因为它效率低。

此外,该函数有一个逻辑错误。

考虑数组{ 0, 0, -1 }

在这种情况下,在循环的第一次迭代中,变量 tempcr 将由于 if 语句而增加

if (A[i]<=A[i+1]){
    tempcr++;
}else if (A[i]>=A[i+1]){
tempdcr++;
}

但在循环的第二次迭代中,变量tempdcr 将增加。

所以该函数会报告该数组是未排序的,尽管它是按降序排序的。

我会通过以下方式定义函数

int is_sorted( const int a[], size_t n )
{
    size_t ascending = 0, descending = 0;

    for (size_t i = 1; ( ascending == 0 || descending == 0 ) && i < n; i++)
    {
        if ( a[i-1] < a[i] ) ++ascending;
        else if ( a[i] < a[i-1] ) ++descending;
    }

    return descending == 0 ? 1 : ( ascending == 0 ? -1 : 0 );
}

如果传递的数组的所有元素彼此相等,则函数认为它是按升序排序的。

正如 @chux - Reinstate Monica 在他的回答中指出的那样,您可以将相应的变量用作布尔对象,而不是计算元素。在这种情况下,函数看起来像

int is_sorted1( const int a[], size_t n )
{
    int ascending = 0, descending = 0;

    for (size_t i = 1; ( ascending == 0 || descending == 0 ) && i < n; i++)
    {
        if ( a[i-1] < a[i] ) ascending = 1;
        else if ( a[i] < a[i-1] ) descending = 1;
    }

    return descending == 0 ? 1 : ( ascending == 0 ? -1 : 0 );
}

【讨论】:

    猜你喜欢
    • 2016-06-29
    • 1970-01-01
    • 2022-06-10
    • 1970-01-01
    • 2012-04-08
    • 2022-11-29
    • 1970-01-01
    • 2018-04-10
    • 1970-01-01
    相关资源
    最近更新 更多