查找 矩阵中行与列中均为最大或者最小的数

本文介绍了一种算法,用于在给定的m*n矩阵中找到同时为所在行和列的最小值或最大值的元素,并输出其坐标和数量。

要求设计一个算法,设置m*n(m=3,n=3)的矩阵元素后,统计这个矩阵中具有以下特征的元素的个数,并输出他们的坐标及数值:他们既是所在行中的最小值又是所在列中的最小值,或者,他们既是所在行中的最大值,又是所在列中的最大值。

 

int findmax(int a[][3],int m,int i)
{
 int max=a[i][0],maxj=0;
 for(int j=0;j<3;j++)
 {
  if(max<a[i][j])
  {
   max=a[i][j];
   maxj=j;
  }
 }
 int k=0;
 while(k<m)
 {
  if(max>=a[k][j])
   k++;
  else
   break;
 }
 if(k==m)
  return max;
 else
  return 0;
}

int findmin(int a[][3],int m,int i)
{
 int min=a[i][0],minj=0;
 for(int j=0;j<3;j++)
 {
  if(min>a[i][j])
  {
   min=a[i][j];
   minj=j;
  }
 }
 int k=0;
 while(k<m)
 {
  if(min<a[k][j])
   k++;
  else
   break;
 }
 if(k==m)
  return min;
 else
  return 0;
}
void main()
{
 int i,j;
 int a[3][3],k=1;
 for(i=0;i<3;i++)
  for(j=0;j<3;j++)
   a[i][j]=k++;
 for(i=0;i<3;i++)
 {
  for(j=0;j<3;j++)
   cout<<a[i][j]<<"   ";
  cout<<endl;
 }
 int m=findmin(a,3,0);
 cout<<m<<endl;
}

<think>我们有一个NumPy矩阵(或组),需要找到一个非零元素的位置。这里的“一个”可以理解为在内存顺序中后出现的非零元素,即按行优先(C顺序)遍历时一个非零元素的位置,或者优先(Fortran顺序)遍历时一个非零元素的位置。但通常,我们按行优先顺序考虑。 然而,用户的问题中提到了“一个非零值的位置”,我们可以理解为在矩阵中按照行和的顺序,从左上到右下遍历,一个非零元素出现的位置。或者更准确地说,是行索引最大,在行索引相同的情况下索引最大的那个非零元素?但这样可能不是真正的一个(因为可能后一行前面有非零,但后一行后面有非零元素)。实际上,我们通常按照内存中的顺序,即行优先(C顺序)来寻找一个非零元素。 在NumPy中,我们可以使用`np.nonzero`或`np.argwhere`来获取所有非零元素的索引,然后找到一个非零元素的索引。但是,注意`np.nonzero`返回的索引组是按行优先顺序排的,所以一个非零元素就是索引组中的一个。 另一种方法是使用`np.flatnonzero`来获取展平组后的非零索引,然后取一个索引,再将其转换为二维索引。 具体步骤如下: 1. 获取矩阵中所有非零元素的索引(行索引和索引)。 2. 由于`np.nonzero`返回的索引组是元组形式,其中第一个组是行索引,第二个组是索引。我们可以取一个非零元素的索引,即每个组的一个元素。 但是注意:`np.nonzero`返回的索引是按行优先顺序排的,所以一个非零元素在返回的索引组的一个位置。 然而,如果我们想要的是在行优先顺序中一个非零元素,那么我们可以这样做: 方法1:使用`np.flatnonzero`获取展平组中的非零索引,取一个索引,然后用`np.unravel_index`将其转换为二维索引。 方法2:使用`np.nonzero`得到所有非零索引,然后取一个(即每个组的一个元素)。 但是注意:`np.nonzero`返回的索引顺序是行优先的,所以方法2是可行的。 示例: 假设矩阵为: ``` [[0, 2, 0], [3, 0, 5], [0, 0, 0]] ``` 非零元素的位置有:(0,1), (1,0), (1,2)。按照行优先顺序,一个非零元素是(1,2)。 使用`np.nonzero`: ```python import numpy as np arr = np.array([[0, 2, 0], [3, 0, 5], [0, 0, 0]]) rows, cols = np.nonzero(arr) # 那么rows = [0, 1, 1], cols = [1, 0, 2] # 一个非零元素的索引就是 (rows[-1], cols[-1]) -> (1,2) ``` 但是,如果矩阵是: ``` [[0, 0, 0], [0, 0, 0], [0, 0, 1]] ``` 那么一个非零元素是(2,2)。 因此,我们可以直接使用: ```python if rows.size > 0: last_nonzero_index = (rows[-1], cols[-1]) else: # 没有非零元素 last_nonzero_index = None ``` 但是,如果用户想要的是在优先顺序中的一个非零元素呢?问题没有明确,但通常我们按行优先。 另外,如果矩阵中有多个非零元素,我们只关心一个(按行优先顺序)。 还有一种情况:我们可能希望找到在二维索引中行最大,在行号相同的情况下最大的元素。这种方法行优先顺序不同吗?实际上,在行优先顺序中,行号是从小到大的,同一行内号从小到大。所以一个非零元素一定是行号最大的,并且在该行中最大的非零元素。但是注意,可能后一行全是0,那么一个非零元素可能在倒第二行。所以实际上,行优先顺序的一个非零元素就是整个矩阵中行最大,在行号相同的情况下最大的那个非零元素。因此,我们也可以这样: 我们可以先找到最大行号,然后在最大行号所在的行中,找到最大号的非零元素。但是这样可能不是行优先顺序的一个,因为行优先顺序是先遍历完一行再遍历下一行,所以最大行号的那一行中的一个非零元素(即该行最大号)就是该行一个非零元素,然后在整个矩阵中,它也是一个非零元素(因为后面的行没有非零元素了)。但是注意,最大行号可能有多行?不,我们找的是整个矩阵中行最大的非零元素,然后在该行中找最大的非零元素。 然而,这种方法需要先找到最大行号,然后再在最大行号的行中找最大号,需要两步操作,不如直接使用`np.nonzero`然后取一个索引简单。 因此,我们采用`np.nonzero`方法。 但是,如果矩阵很大而非零元素很少,`np.nonzero`会返回所有非零元素的索引,我们只需要一个,这样效率可能不高。我们可以考虑从后往前找,这样一旦找到就停止。但NumPy没有直接提供这样的函。我们可以将组展平,然后从后往前找第一个非零元素。 方法3(高效方法): 1. 将组展平(按行优先顺序)。 2. 从后向前找到第一个非零元素的索引(在展平组中的索引)。 3. 将这个一维索引转换为二维索引。 代码: ```python flat_index = None flat_arr = arr.ravel() # 行优先顺序展平 n = len(flat_arr) # 从后向前遍历 for i in range(n-1, -1, -1): if flat_arr[i] != 0: flat_index = i break if flat_index is None: # 没有非零元素 print("没有非零元素") else: # 将一维索引转换为二维索引 last_nonzero_index = np.unravel_index(flat_index, arr.shape) ``` 这种方法在非零元素很少且位于末尾时效率较高,因为只需要遍历到第一个非零元素就停止。但是,如果一个非零元素就在后,那么只需要一次判断。 但是,如果矩阵中非零元素很多,但一个非零元素在后,那么这种方法也是很快的。坏情况是矩阵全0,那么需要遍历整个组。 我们可以根据实际情况选择。如果矩阵不大,两种方法都可以。如果矩阵很大且非零元素集中在后面,方法3更优。 然而,NumPy的`np.nonzero`方法在内部也会遍历整个组,所以如果非零元素很多,我们只需要一个,方法3更优。 因此,我们提供两种方法,并说明适用场景。 方法A(使用`np.nonzero`):代码简洁,适合矩阵不大或非零元素不多的情况。 方法B(逆序遍历展平组):适合大矩阵且非零元素集中在末尾的情况。 下面我们分别实现: 方法A: ```python def last_nonzero_index_np(arr): # 使用np.nonzero nonzeros = np.nonzero(arr) if len(nonzeros[0]) > 0: # 返回一个非零元素的索引 return (nonzeros[0][-1], nonzeros[1][-1]) else: return None ``` 方法B: ```python def last_nonzero_index_loop(arr): flat_arr = arr.ravel() n = flat_arr.size for idx in range(n-1, -1, -1): if flat_arr[idx] != 0: return np.unravel_index(idx, arr.shape) return None ``` 注意:方法B中,我们使用`ravel`展平组,默认是行优先顺序(C顺序)。如果组是Fortran顺序(优先),那么我们需要考虑顺序。但是,通常我们使用行优先。 如果组是Fortran顺序,我们可以通过`order='F'`来展平,但问题没有说明,我们默认按行优先。 另外,我们假设非零元素是指不等于0的元素。但是,如果组中有NaN或Inf,我们是否认为非零?问题没有明确,通常非零是指值不为0。但是,NaN和Inf在比较时,`!=0`是成立的。所以,如果组中有NaN,那么它也会被当作非零。如果需要排除NaN,则需要额外处理。 根据用户的问题,只是说“非零值”,我们按照通常的理解:值不为0。 但是,在引用[3]中,我们看到一个例子:`x = np.array([[0,'a',1],[2,1,None]])`,然后使用`np.nonzero(x)`。注意,这个组中有字符串和None,这会导致整个组成为对象组。在非组的情况下,非零的判断可能不是我们想要的。因此,我们这里假设组是组(整或浮点)。 如果用户需要处理包含非值的组,那么需要另外定义“非零”的概念(例如,非空、非None等)。但问题没有说明,我们只处理组。 因此,我们提供针对组的解决方案。 示例测试: 测试1: ```python arr = np.array([[0,2,0],[3,0,5],[0,0,0]]) print(last_nonzero_index_np(arr)) # 应该返回 (1,2) print(last_nonzero_index_loop(arr)) # 应该返回 (1,2) ``` 测试2: ```python arr = np.array([[0,0,0],[0,0,0],[0,0,1]]) print(last_nonzero_index_np(arr)) # 应该返回 (2,2) print(last_nonzero_index_loop(arr)) # 应该返回 (2,2) ``` 测试3(全0): ```python arr = np.zeros((2,2)) print(last_nonzero_index_np(arr)) # None print(last_nonzero_index_loop(arr)) # None ``` 测试4(只有一个非零元素): ```python arr = np.array([[0,0,0],[0,10,0],[0,0,0]]) print(last_nonzero_index_np(arr)) # (1,1) print(last_nonzero_index_loop(arr)) # (1,1) ``` 注意:在方法A中,`np.nonzero`返回的索引组是按行优先顺序排的,所以一个非零元素在返回的索引组的后位置。在方法B中,我们逆序遍历展平组,找到的第一个非零元素就是行优先顺序中的一个非零元素。 因此,两种方法在行优先顺序下结果一致。 后,我们给出完整代码示例: 我们选择方法A作为主要方法,因为代码简洁,且对于大多情况足够高效。如果矩阵非常大且稀疏,我们可以使用方法B。 但是,方法A需要存储所有非零元素的索引,而方法B只需要一个索引。 因此,在稀疏矩阵的情况下,方法B可能更节省内存。 我们可以根据情况选择实现。 下面,我们以方法B为基础,因为它更高效,并且节省内存。 代码实现: ```python import numpy as np def find_last_nonzero(arr): """ 在二维NumPy组中找到一个非零元素(行优先顺序)的位置。 参: arr (np.ndarray): 二维组 返回: tuple: (行索引, 索引) 或 None(如果没有非零元素) """ # 将组按行优先顺序展平 flat = arr.ravel() n = flat.size # 从后向前遍历 for i in range(n-1, -1, -1): if flat[i] != 0: # 将一维索引转换为二维索引 return np.unravel_index(i, arr.shape) return None # 没有非零元素 ``` 测试示例: ```python # 测试 arr = np.array([[1, 0, 0], [0, 0, 0], [0, 0, 3]]) print(find_last_nonzero(arr)) # 输出 (2,2) ``` 注意:在示例中,一个非零元素是3,位置在(2,2)。 但是,如果组是: ```python arr = np.array([[1, 0, 0], [0, 2, 0], [0, 0, 0]]) ``` 那么一个非零元素是2,位置在(1,1)。 因此,符合预期。 后,我们添加一个注意事项:如果组是优先存储的(Fortran顺序),那么`arr.ravel()`默认还是按行优先展平,除非我们指定`order`参。但是,在创建组时,如果指定了`order='F'`,那么我们需要在`ravel`和`unravel_index`时使用相同的顺序。为了通用性,我们可以考虑组的存储顺序。 但是,为了简单起见,我们假设组是按行优先存储的(C顺序)。如果用户使用的是优先存储的组,那么需要调整。 我们可以通过`arr.flags`查看顺序,但为了简单,我们默认使用行优先。 如果用户希望按照优先顺序来寻找一个非零元素(即按遍历,一个非零元素),那么我们可以修改展平顺序。 但是,问题没有明确要求,我们按行优先顺序实现。 因此,终答案如下:</think>### 在NumPy矩阵查找一个非零元素的位置 在NumPy中查找矩阵一个非零元素的位置,可以通过以下两种高效方法实现: #### 方法1:使用`np.nonzero()`获取所有非零索引后取一个 ```python import numpy as np def find_last_nonzero(matrix): """返回矩阵一个非零元素的位置(行优先顺序)""" # 获取所有非零元素的行索引 rows, cols = np.nonzero(matrix) if len(rows) == 0: return None # 没有非零元素 # 返回一个非零元素的索引 return (rows[-1], cols[-1]) # 示例矩阵 matrix = np.array([ [0, 5, 0], [3, 0, 0], [0, 0, 8] ]) last_pos = find_last_nonzero(matrix) print(f"一个非零元素位置: 行={last_pos[0]}, ={last_pos[1]}") # 输出: 一个非零元素位置: 行=2, =2 ``` #### 方法2:使用展平组和`np.unravel_index()`(内存效率更高) ```python def find_last_nonzero_efficient(matrix): """高效查找一个非零元素位置(适用于大型矩阵)""" flat = matrix.ravel() # 展平为一维组(行优先顺序) # 从后向前查找一个非零元素 for i in range(len(flat)-1, -1, -1): if flat[i] != 0: return np.unravel_index(i, matrix.shape) return None # 没有非零元素 # 使用相同示例矩阵 last_pos = find_last_nonzero_efficient(matrix) print(f"一个非零元素位置: 行={last_pos[0]}, ={last_pos[1]}") ``` #### 关键说明: 1. **索引顺序**:两种方法都基于NumPy的**行优先存储顺序**(C顺序)[^1] 2. **位置定义**:一个非零元素指在行优先遍历中后出现的非零值 - 学表达:设矩阵$A_{m \times n}$,求最大索引$(i,j)$满足: $$i = \max\{k \mid \exists l, A_{k,l} \neq 0\}$$ $$j = \max\{l \mid A_{i,l} \neq 0\}$$ 3. **空矩阵处理**:当矩阵全零时返回`None` 4. **性能对比**: - 方法1:适合中小型矩阵 - 方法2:适合大型稀疏矩阵(无需存储所有非零索引) #### 示例矩阵解析: $$A = \begin{bmatrix} 0 & 5 & 0 \\ 3 & 0 & 0 \\ 0 & 0 & 8 \end{bmatrix}$$ 非零元素位置:(0,1), (1,0), (2,2)。按行优先顺序,一个非零元素是8,位于(2,2)[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值