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