二分查找对杨氏矩阵的理解(含代码实现)

   有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。(代码实现会将所查值的坐标全部输出)
在这里插入图片描述

  现有如上矩阵,我们如何查找一个数是否存在呢?
  首先,我们依据矩阵特征可以知晓,数组上下递增,左右递增。那么对于矩阵的最外围一圈,我们就可以分为四组数据:

矩阵第一行:查找数可能存在在某两个数之间,比如15∈(11,16),那么16此列及右边所有列数就可以全部排除。

矩阵最后一行:同上,15∈(14,20),那么14此列及左边所有列数就可以全部排除。

矩阵第一列:同上,15∈(12,∞),那么就保存12此行及上所有行数。

矩阵最后一列:同上,15∈(-∞,30),那么就保存30此行及下所有行数。
在这里插入图片描述
  实际效果如上
在这里插入图片描述  而在使用一次,我们便能锁定15的位置了。

再找一个11(有兴趣可以找一找其他的数)
在这里插入图片描述

总结:通过不断二分,每一次我们都可以把矩阵分隔成九宫格,而查找数处在中心格,缩小矩阵范围,我们就可以迅速定位查找数的范围(没有经过验证,视乎此法进行2-4次便可结束查找)。

(声明:输出坐标因为行与列会相交,所以会重复输出)

  以下是C语言实现:

  在上一篇文章:二分查找对区间的讨论,我们学习了二分查找两种形式。而在上文缩小矩阵的时候,我们便需要利用二分查找(取闭),确定查找数所在范围。而由于矩阵数据的多样性,在进行缩小矩阵的时候,我们可能将矩阵缩小为仅含一个元素或一列或一行,这时我们就可以利用二分查找(取开),跳出取闭的死循环。

以下 position表示二分查找的方位(哪一行那一列),start表示二分查找的起点,finish表示终点,value表示查找数 N = 1 表示 第一行或列, N = 2 表示 最后一行或列

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

#define row 5

#define col 8//此处可以修改矩阵
//当矩阵缩小为仅含一个元素或一列或一行时  启用
int bin_search(int arr[][col], int position, int start, int finish, int value)
{
	do//取开二分查找
	{
		int mid = (start + finish) / 2;
		if (value > arr[mid][position])
		{
			start = mid + 1;
		}
		else if (value < arr[mid][position])
			finish = mid - 1;
		else if (value == arr[mid][position])
		{
			printf("(%d,%d)",mid, position);
			return 1000;//这些返回值只是为了区分 查找数是通过哪个函数查找出来的
		}
	} while (finish >= start);

	return -1;
}
//行 的 二分查找(取闭)
int row_of_matrix(int arr1[][col], int position, int start, int finish, int value, int N)
//接收第一行值 第一列值 与 最后一列值 /  接收第一列值 第一行值 与 最后一行值
{
	if (value == arr1[position][start] && N == 1)
	//当矩阵第一行第一个元素与查找数相等 那么查找数只会有一个
	{
		printf("(%d,%d)", position, start);
		return 100;
	}
	else if (value == arr1[position][start] && N == 2)
	//当矩阵最后一行第一个元素与查找数相等,那么我们得返回 列数+1 可能右边还存在
	{
		printf("(%d,%d)", position, start);
		return start + 1;
	}
	if (value < arr1[position][start])
	//查找数可能不存在 但我们也要查找一遍 为了代码的可执行性
		return start;
	if (value == arr1[position][finish] && N == 1)
	矩阵第一行最后一个元素与查找数相等, 左边可能存在
	{
		printf("(%d,%d)", position, finish);
		return finish - 1;
	}
	else if (value == arr1[position][finish] && N == 2)
	//矩阵最后一行最后一个元素与查找数相等 查找数只可能存在一个
	{
		printf("(%d,%d)", position, finish);
		return 100;
	}
	if (value > arr1[position][finish])
		return finish;

	do
	{
		int mid = (start + finish) / 2;
		if (value > arr1[position][mid])
			start = mid;
		else if (value < arr1[position][mid])
			finish = mid;
		else if (value == arr1[position][mid] && N == 1)
		//我们要将所有存在的查找数都找出来 那么就必须继续缩小
		{
			printf("(%d,%d)", position, mid);
			return mid - 1;
		}
		else if (value == arr1[position][mid] && N == 2)
		{
			printf("(%d,%d)", position, mid);
			return mid + 1;
		}
	} while (finish - start != 1);

	if (N == 1)//上
		return start;
	if (N == 2)//下
		return finish;
}

int col_of_matrix(int arr2[][col], int position, int start, int finish, int value, int N)//接收最后一行值 第一列值 与 最后一列值 / 接收最后一列值  第一行值 与 最后一行值
//以下参照行的注释理解 完全相似
{
	if (value == arr2[start][position] && N == 1)
	{
		printf("(%d,%d)", start,position);
		return 100;
	}
	else if (value == arr2[start][position] && N == 2)
	{
		printf("(%d,%d)",  start, position);
		return start + 1;
	}
	if (value < arr2[start][position])
		return start;
	if (value == arr2[finish][position] && N == 1)
	{
		printf("(%d,%d)", finish, position);
		return start - 1;
	}
	else if (value == arr2[finish][position] && N == 2)
	{
		printf("(%d,%d)", finish, position);
		return 100;
	}
	if (value > arr2[finish][position])
		return finish;

	do
	{
		int mid = (start + finish) / 2;
		if (value > arr2[mid][position])
			start = mid;
		else if (value < arr2[mid][position])
			finish = mid;
		else if (value == arr2[mid][position] && N == 1)
		{
			printf("(%d,%d)", mid, position);
			return mid - 1;
		}
		else if (value == arr2[mid][position] && N == 2)
		{
			printf("(%d,%d)", mid, position);
			return mid + 1;
		}
	} while (finish - start != 1);

	if (N == 1)//左
		return start;
	if (N == 2)//右
		return finish;
}

int Line_matrix_size(int arr[][col], int row_start, int row_finish, int col_start, int col_finish, int value)
{
	int i1 = col_of_matrix(arr, col_finish, row_start, row_finish, value, 2);
	int i2 = col_of_matrix(arr, col_start, row_start, row_finish, value, 1);
	int j1 = row_of_matrix(arr, row_finish, col_start, col_finish, value, 2);
	int j2 = row_of_matrix(arr, row_start, col_start, col_finish, value, 1);
//每次接收 返回的矩阵限制 范围值
	if (i1 == 100 || i2 == 100 || j1 == 100 || j2 == 100)
		return 1;//没有缩小到一个元素 或 一行 或 一列
	else if (j1 == j2)
	// 为什么 只限定了列相等 因为缩小到一行的数据 我没找到 代码有没有问题
		return bin_search(arr, j1, i1, i2, value);

	Line_matrix_size(arr, i1, i2, j1, j2, value);//递归
}


int main()

{
	int n = 0;
	int num[row][col] = { {1,4,5,11,16,19,25,30},{5,9,12,14,17,20,26,32},{7,10,13,15,19,21,27,34},{11,13,16,18,20,23,28,35},{12,14,20,21,22,25,30,36} };
	//int num[row][col] = { {2,5,7,9,13},{4,6,9,10,14},{7,8,11,13,17},{10,12,14,16,19},{15,17,19,20,24} };
	//int num[row][col] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15},{16,17,18,19,20},{21,22,23,24,25} };
//可以验证
	while (scanf("%d", &n) != EOF)
	{//肯定查找数要在矩阵范围内
		if (n < num[0][0])
			printf("0\n");
		else if (n > num[row - 1][col - 1])
			printf("0\n");
		else
			printf("%d\n", Line_matrix_size(num, 0, row - 1, 0, col - 1, n));
	}
}

//  1  4  5 11 16 19 25 30 定义  i 行 j 列

//  5  9 12 14 17 20 26 32        j max                j min                i max               i min

//  7 10 13 15 19 21 27 34 最上面确定矩阵右界限 最下面确定矩阵左界限 最左边确定矩阵下界限 最右边确定矩阵上界限 

// 11 13 16 18 20 23 28 35

// 12 14 20 21 22 25 30 36

//   1  2  3  4  5  
//   6  7  8  9 10
//  11 12 13 14 15
//  16 17 18 19 20
//  21 22 23 24 25

  • 41
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值