一 复杂度::
学习数据结构的意义在于可以使我们写的程序更加的高效率,而在写程序的时候离不开复杂度的考虑,下面先从2个循环小题目开始 了解为什么要考虑复杂度的概念。
例题1,给定n个元素 求其中奇数的个数
这个题目比较简单 我就这就给出代码了 其主要思想就是我们可以遍历n个元素的数组a 然后依次的辨别他们
int count(int n,int a[])
{
int Count=0;
for(size_t i=0;i<n;i++)
{
//依次判断每次元素是否符合题目要求 提示:判断奇数的方法可以用 %2(模2看余数是否是1 )也可以用&运算符 &1看是结果是否是1 这里%2大家经常用到 我就给&的方法了
if(a[i]&1)
{
Count++;
}
}
return Count;
}
这是测试结果 第一个题目很简单 接着我们给第二个题目,
题目二 给定n个元素的数组a,求有多少组三元组,满足a(i)+a(j)+a(k) 是奇数
这个相比较上面那个会相对于复杂一点点 也可以用嵌套循环的方式来解决 也可以用递归的方式来解决这个问题,注意代码的i j k的取值范围。
int countThree(int n, int start,int a[])
{
int count = 0;
for (size_t i = start; i < n; i++)
{
for (size_t j = i+1; j < n; j++)
{
for (size_t k = j+1; k < n; k++)
{
if ((a[i] + a[j] + a[k]) & 1)
{
count++;
cout << a[i]<<" " << a[j] << " " << a[k] << endl;
}
}
}
}
return count;
}
上述代码虽然可以实验 但是套了三层循环了 还有一种方法可以使得代码量减小 那就是采用递归的方法,递归的方法更加的简洁高效 递归代码如下所示:
int countthree(int n, int a[], int start, int k, int sum)
{
if (k == 0)
{
return (sum & 1) ? 1 : 0; //运算符顺序的关系 记得打();
}
int p = 0;
for (size_t i = start; i < n; i++)
{
p += countthree(n, a, i+ 1, k - 1, sum + a[i]);
}
return p;
}
第二种的递归实现的代码课程稍微有一点难度我解释一下,参数部分分别是 元素个数 数组a 开始start,k就是你要搞几元的,sum就是为了算和用的 记得初始传参要传0;这是我程序中我自己传参的 可以拷贝我的跑一下。
int a[5] = { 0,1,2,3,4 };
int b = countthree(5, a,0,3,0);
int c = countThree(5, 0, a);
当然了如果你要计算偶数改一下三目运算符就可以了 如下::
int countthree(int n, int a[], int start, int k, int sum)
{
if (k == 0)
{
return (sum & 1) ? 0 : 1; //运算符顺序的关系 记得打(); 这个是计算偶数的哈 不要跟计算奇数的弄混了
}
int p = 0;
for (size_t i = start; i < n; i++)
{
p += countthree(n, a, start + 1, k - 1, sum + a[i]);
}
return p;
}
想必到这里关于复杂度的概念你就有一定的意识了 接着我们继续讨论:时间复杂度
时间复杂度定义::算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度
简言之我们用一个表示法 称为大O表示法来表示::
O(n)表示我们写的算法是线性 就是刚才的遍历一次数组就是线性的
表示我们写的算法是平方级别的复杂度 这个大家可以写一个双层循环比如给你一个素组我要求二元的 两个数的加和 是奇数 上面我给了三元的了 我就不写二元的了 大家可以自己写一下。
这个就是我 们写的那个三层循环立方级别的时间复杂度。
二分查找算法的时间复杂度是对数阶的 写一个二分查找的例题吧:
题目3 给定一个有序数组a,查找数组里面的元素b,要求返回数组b的下标
int getmidvalue(int n, int b,int a[])
{
int end = n - 1;
int begin = 0;
while (begin <= end)
{
int mid = (begin + end) >> 1;
if (a[mid] > b)
{
end = mid-1;
}
else if (a[mid] < b)
{
begin= mid+1;
}
else if (a[mid] == b)
{
return mid;
}
}
return -1;
}
判断素数就是根号阶的问题
bool is(int n)
{
if (n == 1)
{
return false;
}
int b = sqrt(n + 0.0);
for (size_t i = 2; i < b; i++)
{
if (n % i == 0)
{
return false;
}
}
return true;
}
空间复杂度::
接下来每日两个oj题目来学习c
(1)
189. 轮转数组 - 力扣(LeetCode) (leetcode-cn.com)//leetcode 连接
void reveserfun(int* arr,int start,int final)
{
while(start<final)
{
int tmp=arr[start];
arr[start]=arr[final];
arr[final]=tmp;
start++;
final--;
}
}
void rotate(int* nums, int numsSize, int k){
k = k % numsSize;
reveserfun(nums,numsSize-k,numsSize-1);
reveserfun(nums,0,numsSize-1-k);
reveserfun(nums,0,numsSize-1);
int i=0;
for(i=0;i<numsSize-1;i++)
{
printf("%d,",nums[i]);
}
printf("\n");
}
这个题目是有多种方法的 比如简单的可以一个一个转换
(2)
这个题的思想及其简单就是再定义一个数组 用定义的减去之前数组的和就可以
int missingNumber(int* nums, int numsSize)
{
int b[numsSize+1];
for(size_t i=0;i<=numsSize;i++)
{
b[i]=i;
}
int c=0;
for(size_t j=0;j<=numsSize;j++)
{
c+=b[j];
}
int d=0;
for(size_t j=0;j<numsSize;j++)
{
d+=nums[j];
}
return c-d;
}