第零章 程序=数据结构+算法?
我们在上程序设计的第一节课的时候,老师就提到了一个概念:程序=数据结构+算法,那么什么是数据结构?什么是算法呢?数据结构研究的是数据在计算机中是以什么方式进行排列组合的;算法研究的是通过什么过程达到最终目的的。
算法是解决问题的特定步骤或明确序列。一个高效的算法可以帮助我们用更少的时间解决十分复杂的问题,而低效的算法则可能花费更多的时间成本和经济成本。这就是我们学习算法的原因。
第一章 交换和排序
1.1 交换
交换算法是一个十分简单的算法,它可以让我们交换两个变量的值。交换算法的基本格式如下(假设我们已经定义a和b并赋初值)
int temp=a;
a=b;
b=temp;
这三句话就完成了交换的算法。
原理如下所述:
首先,用一个临时变量temp存储a的值,此时temp的值是原来a的值;
然后,把b的值赋值给a,此时a的值为原来b的值;
最后,把temp(原来a的值)赋值给b,此时b的值就是原来a的值。
这样,我们就完成了一次a和b的交换。
当然,C++的algorithm库中内置了swap函数,可以直接交换a和b的值。
代码如下:
#include<algorithm>
swap(a,b);
交换算法的别样操作
1.加减法运算(有风险)
a=a+b;
b=a-b;
a=a-b;
提示有风险的原因是加法运算在计算a+b的时候有溢出风险,或者浮点数精度问题导致最后结果可能不是你想要的。
2.乘除法运算(风险比加减法运算更大)
因为除法对于整数的处理是向下取整的,所以不准确的概率会更大,不建议使用。
3. 位运算(无风险,但只适用于整数)
a=a^b;
b=a^b;
a=a^b;
说明:^符号为按位异或运算符,规则为将a和b转化为二进制后,二进制位计算相同的为0,不同的为1。
举个例子:
当a为1,b为2时,a^b的值为3
理由如下(为方便理解,这里采用4位二进制作为示例):
a=1 (0001)
b=2 (0010)
(0001)^(0010)=(0011)=3(记住相同为0,不同为1)
切入正题,在以上的代码中,建议使用临时变量temp存储的算法,尽管它使用了额外的空间。(或者直接用C++的swap(a,b))
1.2 排序
排序算法有很多种,如冒泡排序、选择排序、插入排序、快速排序等。
首先最简单也是最易于理解的就是冒泡排序,代码如下所示:
void bubbleSort(int arr[], int n) {
int i, j, temp;
for (i = 0; i < n-1; i++) { // 外层循环控制遍历的轮数
for (j = 0; j < n-i-1; j++) { // 内层循环控制每一轮的比较和交换
if (arr[j] > arr[j+1]) { // 比较相邻两个元素
// 交换元素
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
冒泡排序的优点就是语法简单,但是缺点就是:太!慢!了!(冒泡排序的时间复杂度为
O
(
n
2
)
O(n^2)
O(n2))
参考快速排序的算法(
O
(
n
log
n
)
O(n \log n)
O(nlogn))
第二章 增删查改
2.1 尾增
纯C语言
#include<stdio.h>
#include<stdlib.h>
struct Array
{
int* arr;
int pos;
};
int main()
{
struct Array a;
int n;
scanf("%d",&n);
a.arr=(int*)malloc(n*sizeof(int));
a.pos=0;
for(int i=0;i<n;i++)
{
int x;
scanf("%d",&x);
*(a.arr+a.pos)=x;
a.pos++;
}
free(a.arr);
return 0;
}
C++
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> arr;
int n;
cin >> n;
for(int i=0;i<n;i++)
{
int x;
cin >> x;
arr.push_back(x);
}
return 0;
}
2.2 尾删
纯C语言
#include<stdio.h>
int main()
{
int arr[10]={1,2,3,4,5};
int len = 5;
if(len>0)
{
len--;
printf("删除成功\n");
}
else
{
printf("数组长度为0,无法删除\n");
}
}
尾删只需要控制数组长度就行
C++用pop_back();来实现vector数组的尾删
2.3 查询
无论是C语言还是C++,顺序表直接查询时间复杂度都是O(1)(下标访问)
对于查找一个特定的目标来说,平均的时间复杂度为O(n)(遍历整个数组)
for(int i=0;i<len;i++)
{
if(arr[i]==target)
{
answer=target;
break;
}
}
对于一个有序数组来说,时间复杂度可以降到O(log n)(二分查找)
#include <stdio.h>
// 二分查找函数
int binarySearch(int arr[], int size, int target) {
int left = 0;
int right = size - 1;
while (left <= right) {
int mid = left + (right - left) / 2; // 防止整数溢出
if (arr[mid] == target) {
return mid; // 找到目标,返回索引
} else if (arr[mid] < target) {
left = mid + 1; // 目标在右半部分
} else {
right = mid - 1; // 目标在左半部分
}
}
return -1; // 未找到目标
}
int main() {
int arr[] = {2, 5, 8, 12, 16, 23, 38, 56, 72, 91};
int size = sizeof(arr) / sizeof(arr[0]);
int target = 23;
int result = binarySearch(arr, size, target);
if (result != -1) {
printf("元素 %d 在数组中的索引是 %d\n", target, result);
} else {
printf("元素 %d 不在数组中\n", target);
}
return 0;
}
第三章 算法竞赛常用算法
3.1 前缀和&差分
前缀和算法就是用一个新数组存储原数组在这个下标之前所有值的和
差分就是用一个数组存储arr[n]-arr[n-1]的值
前缀和算法的C语言表述如下:
int arr[len], prex[len];
prex[0]=arr[0];
for(int i=1,i<len;i++)
{
prex[i]=prex[i-1]+arr[i];
}
差分算法的C语言表述如下:
int arr[len], diff[len];
diff[0]=arr[0];
for(int i=1;i<len;i++)
{
diff[i]=arr[i]-arr[i-1];
}
3.2 双指针
双指针算法使用的首要条件是数组有序。
双指针的一个用法是解决两数之和问题(LeetCode第一题 两数之和)
核心方法是通过指针间的位置关系和移动准则,压缩查找范围,消除暴力解法中的无效计算。
C语言代码如下:
//假设数组升序
int l=0,r=len-1;
while(l<r)
{
if(arr[l]+arr[r]==target)
{
//找到目标
break;
}
else if(arr[l]+arr[r]<target) l++;
else r--;
}
通过双指针算法,可以将时间复杂度从原来的暴力解法(两个for循环) O ( n 2 ) O(n^2) O(n2)降低到 O ( n ) O(n) O(n)。
1467



被折叠的 条评论
为什么被折叠?



