杨氏矩阵问题

杨氏矩阵:一个二维数组,数组的每行从左至右是递增的,每列从上往下也是递增的。
例如:
数组:
1 3 4
2 4 5
4 5 6

1 2 3
4 5 6
7 8 9
问题:在这样的数组中查找一个数字是否存在,时间复杂度小于O(N)。
显然,时间复杂度小于O(n)是指,充分利用杨氏矩阵的特征,而不能把整个矩阵遍历去寻找。
我的第一想法
看到这个题,我的第一个思路是把二维数组画成一个矩形,然后选定一个数字。分三种情况来分析查找过程。1.选定数字=指定查找数字,结束查找。2.选定数字>指定查找数字,查找范围缩小至选定数字的下边或者右边。3.选定数字<指定查找数字,查找范围缩小至选定数字的上边或者右边。举一个例子,假设如图二维数组,假设选定数字为5,那么查找的数字不等于选定数字的情况就是这样,黄色代表查找范围。
在这里插入图片描述
因为我们的指定查找数会出现在两个查找区域,通过图片,我们很清楚就能观察到,两个区域是有重叠部分的,橙色代表重叠部分。所以我就变得手无足措了。
第二想法
试试把数组的右上角作为选定数,还是以上面的例子,如下图a。即3为选定数字,假设查找数字为7,第一次比较,7>3,因为3是第0行最大的数字,则7不可能出现在3所在行,所以将3所在行数剔除,得到图b,那么此时选定数字变为6,因为6<7,所以剔除6所在行,得到图c。则7一定在此时9所在行中。
在这里插入图片描述
那么我们可以挖掘出来的代码思路是:当选定数=指定查找数时,返回对应数字下标输出,当选定数<指定查找数时,行数++,当选定数>指定查找数时,列数–;
C代码如下

#include<stdio.h>
#include<stdlib.h>

void Find_number(int arr[3][3], int *px, int *py, int key)//*px和*py代表行和列,找到后返回下标的值存放在里面
{
	int x = 0;
	int y = *py - 1;//定位最右上角的数字
	while ((x <= (*px-1))&&(y>=0))
	{
		if (arr[x][y] == key)
		{
			*px = x;
			*py = y;
			return;//结束函数
		}
		else if (arr[x][y] > key)
		{
			y--;
		}
		else //arr[x][y]<key
		{
			x++;
		}
	}
	*px = -1;
	*py = -1;
}
int main()
{
	int arr[][3] = { 1,2,3,4,5,6,7,8,9 };
	int num = 0;
	int x = 3;//行数为3
	int y = 3;//列数为3
	scanf("%d", &num);
	Find_number(arr,&x,&y,num);//x和y传相应的地址
	if (x!=-1&&y!=-1)
	{
		printf("find it,the location is %d,%d",x,y);
	}
	else
		printf("can't find\n");
	system("pause");
	return 0;
}

但在写这个函数的时候我一开始陷进了一个误区,因为我想我要拿到坐标x和坐标y,所以我知道不能通过通过写一个int函数来return得到两个下标的值。所以我写了一个void类型的函数,然后通过实参传址,保存到了地址里面 ,通过在函数里面修改实参的值,来得到两个下标。
然后我就觉得:1.这里用void型函数的原因是,要返回两个下标 ,所以用void类型函数。
我还自己得到一个总结:2.要得到两个或两个以上的返回值,就用void型函数。

然而以上这两句话是完全错误的

这里我们要得到两个下标的值是没错,但是我们绝对不能说所以要使用void型函数,这里和void没有任何关系。
因为这里也可以用int或者是char(如下面代码),也是通过实参传址改变实参的值。找到返回1或者true,找不到返回0或false。而前面所说的不能用int函数是指不能直接通过return得到两个下标的值。

int Find_number(int arr[3][3], int *px, int *py, int key)//*px和*py代表行和列,找到后返回下标的值存放在里面
{
	int x = 0;
	int y = *py - 1;//定位最右上角的数字
	while ((x <= (*px-1))&&(y>=0))
	{
		if (arr[x][y] == key)
		{
			*px = x;
			*py = y;
			return 1;
		}
		else if (arr[x][y] > key)
		{
			y--;
		}
		else //arr[x][y]<key
		{
			x++;
		}
	}
	return 0;
}
int main()
{
	int arr[][3] = { 1,2,3,4,5,6,7,8,9 };
	int num = 0;
	int x = 3;//行数为3
	int y = 3;//列数为3
	int result = 0;
	scanf("%d", &num);
	result=Find_number(arr,&x,&y,num);//x和y传相应的地址
	if (result)
	{
		printf("find it,the location is %d  %d\n", x, y);
	}
	else
		printf("can't find it\n");
		system("pause");
	return 0;
}
发布了50 篇原创文章 · 获赞 30 · 访问量 9178

猜你喜欢

转载自blog.csdn.net/qq_42913794/article/details/89512505