二分,栈和队列,结构体内存对齐

1.二分查找

二分查找也叫折半查找,是一种快速搜索的算法,对于一组有序数字进行快速搜索,在较短的时间内得出结果。

思路:

1.首先从数据的中间元素与所要查找的元素进行比较,如果该元素是所查找的元素,则结束程序,否则执行第二步操作

2.如果所查找的元素大于/小于中间元素,则在数组大于/小于中间元素的那一半区域查找,然后重复步骤1的操作。

3.如果某一步的数据为空则找不到该元素

例题

题目描述

输入 n(n\le10^6)n(n≤106) 个不超过 10^9109 的单调不减的(就是后面的数字不小于前面的数字)非负整数 a_1,a_2,\dots,a_{n}a1​,a2​,…,an​,然后进行 m(m\le10^5)m(m≤105) 次询问。对于每次询问,给出一个整数 q(q\le10^9)q(q≤109),要求输出这个数字在序列中第一次出现的编号,如果没有找到的话输出 -1 。

输入格式

第一行 2 个整数 n 和 m,表示数字个数和询问次数。

第二行 n 个整数,表示这些待查询的数字。

第三行 m 个整数,表示询问这些数字的编号,从 1 开始编号。

输出格式

m 个整数表示答案。

输入输出样例

输入 #1复制

11 3
1 3 3 3 5 7 9 11 13 15 15
1 3 6

输出 #1复制

1 2 -1 
#include <stdio.h>
int a[1000010] = { 0 };
int judge(int l, int r,int k)
{
	while (l < r)
	{
		int mid = (l + (r-1)) / 2;
       //防止l+r溢出
		if (a[mid] >= k)
			r = mid;
		else if (a[mid] < k)
			l = mid+1;
	}
	if (a[l] == k)//找到返回位置
		return l;
	else//未找到返回-1
		return -1;
}
int main()
{
	int n, q;
	scanf("%d%d", &n, &q);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	for (int i = 1; i <= q; i++)
	{
		int a;
		scanf("%d", &a);
		int t = judge(1, n, a);
		printf("%d ", t);
	}
	return 0;
}

2.结构体的内存对齐

对于结构体来讲,两个结构体的内部存有相同的元素,但元素的顺序不同,结果导致这两个结构体的大小也就不相同

#include <stdio.h>
struct
{
	int a;
	char b;
	char c;
}s1;
struct
{
	char a;
	int b;
	char c;
}s2;
int main()
{
	printf("%d\n", sizeof(s1));
	printf("%d\n", sizeof(s2));
	return 0;
}

其结果为

这是因为计算机在为结构体分配空间大小是遵循内存对齐原则:

1.结构体的第一个成员在结构体内存偏移量为0的地址处

2.其他成员要对齐到某个数字(对齐数)的整数倍的地址处

对齐数=编译器默认的一个对齐数与该成员大小的较小值。

vS中默认的值为8

3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

以上例分析,对于s1的存放方式

此时只占了六个字节,但是最大的对齐数为4,需要在加上两个字节,才能构成4的倍数,故s1占了八个字节 

对于s2

当存放完char类型后,该存放int类型,而int类型的对齐数为4,存放它的内存偏移量需要为4的倍数,故浪费掉三个字节从第四个开始存int,接着的char同理,存完后只占了九个字节,而最大的对齐数是4,仍需要再扩展三个字节,故s2占了12个字节 

为什么存在内存对齐?

1.平台原因(移植原因)︰不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

⒉性能原因︰数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

总体来说︰结构体的内存对齐是拿空间来换取时间的做法。
 

3.栈和队列都是一种特殊的线性表

(1)、对于一个栈来说:它只允许在固定的一段进行插入或者删除元素,在进行数据插入或者删除的一段称之为栈顶,剩下的一端称之为栈顶。其遵循的原则是后进先出。有三大核心操作,分别是入栈、出栈、取栈顶元素

栈仅是在表尾进行插入、删除操作的线性表。

例如、栈 s={a(1),a(2),a(3),........a(n-1),a(n)},其中a(1)为栈底元素,a(n)为栈顶元素,插入元素到栈顶(表尾)的操作即入栈,删除栈顶(表尾)的元素即出栈

 

 

(2)、对于一个队列来讲:它允许在一端进行插入数据,在另一端进行删除数据的。队列里边有队首,队尾,队首元素。其遵循的原则是先进先出。也有三大核心操作,分别是入队列,出队列,取队首元素

队列是在表头进行删除,表尾进行插入的线性表

3)、栈和队列存在的意义:栈和队列存在的意义就是减少线性表的基本操作,提取常用操作,让人们使用起来更方便,更不容易出错。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值