三个数字排序的简单方法

25
有没有更简单更好的方法来解决这个问题呢?因为:
1. 我使用了太多的变量。 2. 我使用了太多的 if else 语句。 3. 我使用了蛮力法来解决这个问题。
请编写一个程序,接收三个整数作为输入,并按升序输出这些数字。 请勿使用循环/数组。
#include <stdio.h>
main(){
   int no1;
   int no2;
   int no3;
   int sto;
   int hi;
   int lo;

   printf("Enter No. 1: ");
   scanf("%d", &no1);
   printf("Enter No. 2: ");
   scanf("%d", &no2);         
   printf("Enter No. 3: ");
   scanf("%d", &no3);

   if (no1>no2) {   
      sto=no1;    
      lo=no2;   
   } else {
      sto=no2;  
      lo=no1;  
   } 
   if (sto>no3) { 
      hi=sto;    
      if(lo>no3){         
         sto=lo;                
         lo=no3;
      }else {
         sto=no3;      
      }         
   }else hi=no3; 

   printf("LOWEST %d\n", lo);
   printf("MIDDLE %d\n", sto);
   printf("HIGHEST %d\n", hi);  

   getch(); 
}    

是的,有更好的方法,但你需要使用循环和数组。也许对于入门课程来说,你的答案就是他们想要的答案。有一些方法可以使用for/while循环(递归,goto等)进行循环。还有一些方法可以获得类似于没有索引的数组(int *ptr = malloc (3 * sizeof(int)),然后使用 *(ptr+index) 进行索引)。但我认为这不是他们想要的。 - Lou Franco
提示:如果你有3个数字a、b和c,min(a, min(b, c))是最小的,max(a, max(b, c))是最大的,而且已知最小和最大的数,很容易找到第三个数。 - gdj
13个回答

32
if (a > c)
   swap(a, c);

if (a > b)
   swap(a, b);

//Now the smallest element is the 1st one. Just check the 2nd and 3rd

if (b > c)
   swap(b, c);

注意:Swap会交换两个变量的值。


这也应该解释为什么解决方案是有效的;也就是说,以某种方式谈论排序网络。 - undefined

11

将三个变量称为xyz,然后:

if (x > y) swap(x, y);
if (y > z) swap(y, z)
if (x > y) swap(x, y);

编写swap函数留给读者练习。提示:您可能需要使用指针。


你不如不把这个问题留给读者自己解决,直接提供一个完整的解决方案怎么样?另外,你能解释一下为什么这是一个有效的解决方案(排序网络),而不仅仅是发布它吗? - undefined

10
#include <stdio.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
int main(){
   int a, b, c;
   int hi;
   int lo;

   printf("Enter No. 1: ");
   scanf("%d", &a);
   printf("Enter No. 2: ");
   scanf("%d", &b);         
   printf("Enter No. 3: ");
   scanf("%d", &c);

   lo = min(min(a, b), c);
   hi = max(max(a, b), c);
   printf("LOWEST %d\n", lo);
   printf("MIDDLE %d\n", a+b+c-lo-hi);
   printf("HIGHEST %d\n", hi);  

   getchar(); 
}    

1
数学上,a+b+c-lo-hi是正确的,但在计算机运算中可能会导致溢出。因此,交换版本更加安全。 - Christian Ullenboom
2
为什么要使用宏而不是普通函数? - Jarod42
1
Jarod42,为什么不呢? - Vovanium

5

如果您想将值分类到新的外部变量中,实际上可以在没有临时变量的情况下进行交换:

void sort(int a, int b, int c, int *min, int *mid, int *max) {
    min = a;
    mid = b;
    max = c;
    if (min > mid) { mid = a; min = b; }
    if (mid > max)
    {
        max = mid;
        mid = c;
        if (min > mid)
        {
            mid = min;
            min = c;
        }
    }
}

这个方法之所以有效,是因为最后一次交换测试只有在第二个测试成功时才真正需要(否则它将只是第一个测试的重复,由于我们已经对那些变量进行了排序,所以它将被定义为失败)。
因此,我们可以跟踪每个原始变量的赋值并避免交换本地变量。

2
#include <stdio.h>
int main()
{
  int a;
  int b;
  int c;

  //Temporary storage variable
  int t = 0;

  printf("Enter No. a: ");
  scanf("%d", &a);
  printf("Enter No. b: ");
  scanf("%d", &b);         
  printf("Enter No. c: ");
  scanf("%d", &c);

  if (a > b) 
  {   
      t = a;    
      a = b;
      b = t;
  }
  if (a > c)
  {
    t = a;
    a = c;
    c = t;
  }
  if (c < b)
  {
    t = c;
    c = b;
    b = t;
  }
  
  printf("a = %d < b = %d < c = %d", a, b, c);
  
  return 0;
}

2
虽然这段代码可能为问题提供了解决方案,但最好添加一些上下文来说明它的原理和工作方式。这可以帮助未来的用户学习并将这些知识应用到他们自己的代码中。当代码得到解释时,你也很可能会获得积极的反馈,比如点赞。 - borchvm

1
要找到3个值的最小值中间值最大值,您可以使用三元运算符。您可以在代码的主体内完成所有工作,或者您可以将minof3midof3maxof3计算分开成可重复使用的函数。
对于最小值最大值,您只需进行3个可能比较中的2个,并返回结果的比较。对于中间值,您也是这样做的,但是计算3个值的最小值和最大值,然后根据最小值最大值检查所有3个值,以找到既不是最小值也不是最大值的值。(您可以通过声明最小值和最大值作为变量并在那里进行消除来在代码的主体部分完成此部分,而不需要额外的函数)。
将所有部分组合在一起,您可以执行类似于以下操作,它将前3个参数作为排序的值(如果未指定所需值,则使用默认值99、231、8)。
#include <stdio.h>
#include <stdlib.h>

/** direct ternary comparison of 3 values */
long minof3 (long a, long b, long c) {
    long x = a < b ? a : b,
         y = a < c ? a : c;
    return x < y ? x : y;
}

long maxof3 (long a, long b, long c) {
    long x = a > b ? a : b,
         y = a > c ? a : c;
    return x > y ? x : y;
}

long midof3 (long a, long b, long c) {
    long x = a < b ? a : b,
         y = a > b ? a : b,
         z = y < c ? y : c;
    return x > z ? x : z;
}

int main (int argc, char **argv) {

    long x = argc > 1 ? strtol (argv[1], NULL, 10) : 99,
         y = argc > 2 ? strtol (argv[2], NULL, 10) : 231,
         z = argc > 3 ? strtol (argv[3], NULL, 10) : 8;

    /* strtol validations omitted for brevity */

    printf ("\n sorted values : %ld, %ld, %ld\n",
            minof3 (x, y, z), midof3 (x, y, z), maxof3 (x, y, z));
}

示例用法/输出
$ ./bin/sort3
 sorted values : 8, 99, 231

$ ./bin/sort3 -23 -281 1031
 sorted values : -281, -23, 1031

(是的,我知道这是一个旧帖子,但考虑到最近有关swap函数后面隐藏了代码的评论,需要提供一个完整的示例)。


1
下面的代码只执行2次(最佳情况)到3次(最坏情况)条件测试,没有赋值操作或任何额外的变量:
void from(int ref, int x, int y) {
    (ref < y) ? ((x < y) ? echo(ref,x,y) : echo(ref,y,x)) : echo(y,ref,x);
}
void printSorted(int a, int b, int c) { (a < b) ? from(a,b,c) : from(b,a,c); }

基本调用(为简单起见避免使用scanf()):
void echo(int _1st, int _2nd, int _3rd) { printf("%d %d %d", _1st, _2nd, _3rd); }
int main() {
    printSorted(2,3,1); //Output: 1 2 3
}

0
一个紧凑的解决方案,没有魔法swap()函数,绕过int溢出,并滥用数组:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {

    int a = atoi(argv[1]);
    int b = atoi(argv[2]);
    int c = atoi(argv[3]);

    int ab[] = {a, b}, bc[] = {b, c};
    int smaller[] = {ab[a > b], bc[b > c]}, larger[] = {ab[a < b], bc[b < c]};
    int smallest = smaller[a > c], largest = larger[a < c];
    int middle = (a - smallest) + (b - largest) + c;

    printf("%d, %d, %d\n", smallest, middle, largest);

    return 0;
}

使用方法

> ./a.out 2147483647 2147483645 2147483646
2147483645, 2147483646, 2147483647
> 

0
这是一个解决方案,如果你只想对3个数字进行排序的话。
void orderOfThree(int *a1, int *a2, int *a3){
        
     if (*a1 > *a2){ // 6 4 3
        int temp_number = *a1;
        *a1 = *a2;
        *a2 = temp_number;
     }
     
     if (*a2 > *a3){ // 4 3 6
         int temp_number = *a2;
         *a2 = *a3;
         *a3 = temp_number;
     }
     
     if (*a1 > *a2){ // 3 4 6
        int temp_number = *a1;
        *a1 = *a2;
        *a2 = temp_number;
     }
       
}


随意更改*指针参数为您所需的输入。

这本质上是一个用于三个元素的排序网络。如果答案能够解释其背后的理论而不仅仅提供示例代码,那就太好了。 - undefined

0
在沃尔特·E·布朗的一次演讲中,他讨论了在许多算法中使用无操作符的用法,并且“展示了在直接使用原始操作符<时容易犯错的情况”。那是一次关于C++标准库的演讲,但他展示的算法之一正好是一个三项排序。
用C语言编写,他提出的函数看起来像这样:
#include <stdbool.h>

bool out_of_order(int a, int b) {
  return b < a;
}

bool in_order(int a, int b) {
  return !out_of_order(a, b);
}

void swap(int *a, int *b)
{
  int temp = *a;
  *a = *b;
  *b = temp;
}

void sort2(int *a ,int *b) {
  if ( out_of_order(*a, *b) )
    swap(a, b);
}

void sort3(int *a, int *b, int *c) {
  sort2(a, b);
  if ( in_order(*b, *c) )
    return;                     // <-- Note the early returns
  swap(b, c);
  if ( in_order(*a, *b) )
    return;                     // <--
  swap(a, b);
}

他还提到这实际上是一个(可能不熟悉的)冒泡排序的实现2
如果你对多个函数调用感到担心,请看一下使用GCC编译并使用-O2优化选项生成的汇编代码。
sort3:
        mov     eax, DWORD PTR [rsi]
        mov     ecx, DWORD PTR [rdi]
        cmp     eax, ecx
        jge     .L8
        mov     DWORD PTR [rdi], eax
        mov     eax, ecx
        mov     DWORD PTR [rsi], ecx
.L8:
        mov     ecx, DWORD PTR [rdx]
        cmp     ecx, eax
        jge     .L7
        mov     DWORD PTR [rsi], ecx
        mov     DWORD PTR [rdx], eax
        mov     edx, DWORD PTR [rsi]
        mov     eax, DWORD PTR [rdi]
        cmp     edx, eax
        jge     .L7
        mov     DWORD PTR [rdi], edx
        mov     DWORD PTR [rsi], eax
.L7:
        ret

将其与被接受答案中的代码生成的结果进行比较:3
sort_three:
        mov     eax, DWORD PTR [rdi]
        mov     ecx, DWORD PTR [rdx]
        cmp     eax, ecx
        jle     .L13
        mov     DWORD PTR [rdi], ecx
        mov     DWORD PTR [rdx], eax
        mov     eax, DWORD PTR [rdi]
.L13:
        mov     ecx, DWORD PTR [rsi]
        cmp     ecx, eax
        jge     .L14
        mov     DWORD PTR [rdi], ecx
        mov     ecx, eax
        mov     DWORD PTR [rsi], eax
.L14:
        mov     eax, DWORD PTR [rdx]
        cmp     eax, ecx
        jge     .L12
        mov     DWORD PTR [rsi], eax
        mov     DWORD PTR [rdx], ecx
.L12:
        ret

你能找出不同之处吗?

1) 有多个版本:
正确计算最小值、最大值等 - Walter E Brown - CPPP 2021
Walter E. Brown - 正确计算最小值、最大值等 - Meeting C++ online
itCppCon21 - 极值:正确计算最小值和最大值(Walter E Brown)

2) https://en.wikipedia.org/wiki/Bubble_sort

3) 嗯,稍微修改了一下,我不得不将那些变量改为指针:https://godbolt.org/z/9Yn8xEM68


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接