NET常见类系列探究——Array.Sort的方法排序本质

本文深入探讨了.NET中Array.Sort方法的工作原理,特别是针对复合类型的排序机制。解释了IComparable和IComparer接口的作用,并通过示例代码展示了如何实现自定义排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       不知大家是否注意到NET中有一个默认升序排序方法,位于SystemArray类中,属于静态方法。当你使用整数或者字符串数组作为参数传入时它将执行排序操作,代码如下所示:

 (VB.NET):

 

Dim g()as Integer=New Integer(){1,2,4,5,3}
Array.Sort(g)  

(C#):

 

int[]g={1,2,4,5,3};
Array.Sort(g);   
//结果:1,2,3,4,5

     

     但是你是否考虑这样一个问题——构成数组的类型不是单纯的一个“基本类型”,而是一个复合类型(比如结构或类),假如有一个Student类,定义代码如下:

 

(VB.NET):

 

ContractedBlock.gifExpandedBlockStart.gifCode
Public Class Student
        
Private stuname As string=Nothing
        Private score As double =0.0

        
Public Property StuName()As string
            
Get
                
return stuname
            
End Get

            
Set(Value as String)
                stuname
=Value
            
End Set
        
End Property

        
Public Property Score()As dobule            

            Get
                
return score
            End Get
            Set(Value as double)
                score
=Value
            
End Set
        
End Property

End Class
 

 

(C#):

 
ContractedBlock.gifExpandedBlockStart.gifCode
public class Student
    {
        
private string stuname=null;
        
private double score=0.0;

        
public string StuName
        {
            
get
            {
                
return stuname;
            }
            set
            {
                stuname
=value;
            }
        }

        
public string Score
        {
            
get
            {
                
return score;
            }
            set
            {
                score
=value;
            }
        }
    }

 

     然后将Student的相应属性赋值,构成数组stus,(这儿代码省略);然后调用Array.Sort (stus)排序……,结果如何?

 

     很遗憾,程序崩溃无法正常运行。并且抛出了一个“System.InvalidOperationException”异常,提示说“必须至少有一个对象实现IComparable”。

         IComparable是什么接口?为什么实现它就可排序了呢?我们可以先按照提示,写一个IComparable,然后鼠标右键,点击“查看定义”,这样VS将自动查询该接口的原始定义:

 

(VB.NET):

ContractedBlock.gifExpandedBlockStart.gifCode
Public Interface IComparable
    
Function CompareTo (obj As ObjectAs Integer
End Interface

 (C#):

public interface IComparable
{
    
int CompareTo (Object obj);
}

 

再进一步查看该方法的说明,您发现:当返回值大于0,则当前实例大于obj;当返回值小于0,则当前实例小于obj;等于0则两者相等。因此它是一个类比较排序接口。

    如果我们将上面的类继承了该接口,那么就可以进行排序了,代码如下:

 

(VB.NET):

ContractedBlock.gifExpandedBlockStart.gifCode
Public Class Student Implements IComparable
        
Private stuname As string=Nothing
        
Private score As double =0.0

        
Public Property StuName()As string
            
Get
                
return stuname
            
End Get

            
Set(Value as String)
                stuname
=Value
            
End Set
        
End Property

        
Public Property Score()As dobule            
            
Get
                
return score
            
End Get
            
Set(Value as double)
                score
=Value
            
End Set
        
End Property
 
       
Public Function CompareTo (obj As ObjectAs Integer
            
Return (score-CType(obj,Student).score)
       
End Function
End Class

(C#):

ContractedBlock.gifExpandedBlockStart.gifCode
public class Student : IComparable
{
        
private string stuname=null;
        
private double score=0.0;

        
public string StuName
        {
            
get
            {
                
return stuname;
            }
            set
            {
                stuname
=value;
            }
        }

        
public string Score
        {
            
get
            {
                
return score;
            }
            set
            {
                score
=value;
            }
        }


          public int CompareTo (Object obj)
          {
              
return score-((Student)obj).score;
          }
}
 
 

     此时您再使用Array.Sort(stus)方法就不会出现异常,而是按照分数进行排序了。

 

       为什么会产生这样一种情况呢?实际上,当您使用Array.Sort(stus)时候,ArraySort方法内部完成了如下操作:

 

(VB.NET):

ContractedBlock.gifExpandedBlockStart.gifCode
Public Sub Sort(Of T)(stus As T)
    
For(排序外循环)
         
For(排序内循环)
               
if (stus[i].CompareTo(stus[i+1])>0)        '第i个数比第i+1个数大
                    两个数字相互交换
          
Next
    
Next
End Sub

(C#):

ContractedBlock.gifExpandedBlockStart.gifCode
public void Sort<T> (T[] stus)
for (排序外循环)
{
    
for (排序内循环)
    {
        
if (stus[i].CompareTo(stus[i+1])>0)        //第i个数比第i+1个数大
        两个数字相互交换;
    }
}
 

这个代码之所以不使用明码,而用伪代码取而代之,是因为排序循环依赖具体实现的方法(选择、冒泡、插入……)。这里只是给出一个思想,诉您CompareTo作用是用于比较两个结构或类(复合类型)的“大小”(根据某个“可比性”)。所以你如果没有实现IComparable接口,类本身不会具有“CompareTo”方法,自然运行要报错了。当然,您即使不继承此类,直接写一个CompareTo在类里头也可以,因为接口只要找寻到“同名函数、同类型返回以及相同的参数列表”的函数就可以了

       进一步扩充——可能有读者要问:那么如果我要实现两种排序方法:“有时按姓名升序,有时按成绩降序”怎么办?读者可以查找该方法的重载函数,定义如下:

 

Array.Sort (T[] objs, IComparer<T> comparer)

 

IComparer<T>接口定义如下:

 

 

(VB.NET):

 

ContractedBlock.gifExpandedBlockStart.gifCode
Public Interface IComparer(Of T)
  
Function CompareTo(obj1 As T,obj2 As T) As Integer
End Interface

(C#):

 

ContractedBlock.gifExpandedBlockStart.gif Code
public interface IComparer<T>
{
    
int CompareTo (T obj1, T obj2);
}

 

同样地,当返回值大于0obj1>obj2;返回值等于0obj1=obj2;返回值小于0obj1<obj2

 

我们可以重新写两个“姓名排序”和“成绩排序”的类,分别继承IComparer<T>接口,代码如下:

(VB.NET):

 
ContractedBlock.gifExpandedBlockStart.gifCode
Public Class SortByName Implements IComparer(Of Student)   
      
Public Function CompareTo (obj1 As Student,obj2 As Student)As Integer
             
Return obj1.StuName.CompareTo(obj2.StuName)    '字符串内置具有CompareTo方法比大小,作用同IComparable的那个CompareTo。
       End Function
End Class


Public Class SortByScore Implements IComparer(Of Student)   
        
Public Function CompareTo (obj1 As Student,obj2 As Student)As Integer
                   
Return obj1.Score-obj2.Score
        
End Function
End Class

(C#):

 
ContractedBlock.gifExpandedBlockStart.gifCode
public class SortByName : IComparer<Student>
{    
        
public int CompareTo (Student obj1, Student obj2)
          {
              
return obj1.StuName.CompareTo(obj2.StuName);    //字符串内置具有CompareTo方法比大小,作用同IComparable的那个CompareTo。
          }
}


public class SortByScore : IComparer<Student>
{    
        
public int CompareTo (Student obj1, Student obj2)
          {
                   
return obj1.Score-obj2.Score;
          }
}

 

     调用时,只要按照“Array.Sort(排序的数组, 继承IComparer<T>的类)”即可。如上面要对姓名按照升序排列,只要Array.Sort (stus, new SortByName()) 就可以了。

     这个重载方法内部实现如下:

 

 

(VB.NET):

 

ContractedBlock.gifExpandedBlockStart.gifCode
Public Sub Sort(Of T)(stus As T(), IComparer(Of T) comparer)
        
For (排序外循环)
                
For (排序内循环)
                          
If (comparer.CompareTo(stus(i),stus(i+1))>0)      '第i个数比第i+1个数大
                               两个数字相互交换;
                
Next
        
Next
End Sub

(C#):

 

ContractedBlock.gifExpandedBlockStart.gifCode
public void Sort<T> (T[] stus, IComparer<T> comparer)

{
        
for (排序外循环)
          {
                
for (排序内循环)
                      {
                          
if (comparer.CompareTo (stus[i],stus[i+1])>0)        //第i个数比第i+1个数大
                               两个数字相互交换;
                      }
          }
}

转载于:https://www.cnblogs.com/serviceboy/archive/2008/08/30/1280089.html

### Java 中 `Arrays.sort` 方法的自定义排序 在 Java 中,可以通过传递实现了 `Comparator` 接口的对象给 `Arrays.sort()` 来实现数组元素的自定义排序逻辑。这允许按照特定条件而非自然顺序对数组中的元素进行排序。 对于基本型的数组(如 `int[]`, `double[]`),无法直接应用自定义比较器;但对于对象数组(如 `Integer[]`, `String[]` 或者任何其他实现了 `Comparable` 接口的对象数组),则完全可以这样做[^3]。 下面是一个具体的例子,展示了如何通过匿名内部以及更简洁的 Lambda 表达式来完成这一过程: #### 使用匿名内部的方式 ```java import java.util.Arrays; import java.util.Comparator; public class CustomSortExample { public static void main(String[] args) { Integer[] numbers = {9, 8, 7, 2, 3, 4, 1, 0, 6, 5}; // 创建一个新的 Comparator 实例用于降序排列整数 Arrays.sort(numbers, new Comparator<Integer>() { @Override public int compare(Integer num1, Integer num2) { return num2.compareTo(num1); } }); System.out.println("Sorted in descending order: " + Arrays.toString(numbers)); } } ``` #### 使用 Lambda 表达式的简化写法 ```java import java.util.Arrays; public class CustomSortLambdaExample { public static void main(String[] args) { Integer[] numbers = {9, 8, 7, 2, 3, 4, 1, 0, 6, 5}; // 使用 lambda 表达式简化代码 Arrays.sort(numbers, (num1, num2) -> num2 - num1); System.out.println("Sorted in descending order with lambda: " + Arrays.toString(numbers)); } } ``` 这两种方法都可以有效地改变默认的升序行为,转而根据指定规则重新安排数组内的元素位置。当涉及到更为复杂的业务需求时,比如基于多个字段组合排序或是处理非标准的数据型,则推荐使用更加灵活且易于维护的第一种方式——即创建专门的 `Comparator` 实例[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值