算法
数据结构中的算法,指的是数据结构所具备的功能
解决特定的问题的方法,是仙人优秀的经验总结
算法的基本特征
1.有穷性(Finiteness):算法的有穷性是指算法必须能在执行bai有限个步骤之后终止;
2.确切性(Definiteness):算法的每一步骤必须有确切的定义;
3.输入项(Input):一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0个输入是指算法本身定出了初始条件;
4.输出项(Output):一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出的算法是毫无意义的;
5.可行性(Effectiveness):算法中执行的任何计算步骤都是可以被分解为基本的可执行的操作步,即每个计算步都可以在有限时间内完成(也称之为有效性)。
如何评价一个算法
时间复杂度:由于计算机的性能不同,无法准确的统计出一个算法执行所需要的时间。
因此我们用算法执行的次数来代表算法的时间复杂度
O(公式) =
时间复杂度
//O(1)
printf("%d");
//O(n)
for (int i=0;i<n;i--);
//O(logn)
for(int i=n;i>=0;i/=2)
//O(nlogn)
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j/=2)
{
printf("%d");
}
}
//O(n^2)
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
printf("%d");
}
}
分治
把一个大且复杂的问题,分解称很多小而简单的问题,利用计算机计算能力来实现,例如循环,递归
查找算法
顺序查找
对待查找的数据没有任何要求,从头到尾逐一查找,适合在小规模的数据查找中常见
缺点:效率低
时间复杂度:O(n)
二分查找
待查找的数据必须是有序的,从数据的中间查找判断大小从另一半开始找
时间复杂度:O(logn)
块查找
是一种对数据进行处理的思想,不是一种特定的算法,当数据量很多时,可以对数据进行分块
分门别类查找,还有类似的 权重查找
#include<stdio.h>
#include<stdlib.h>
#define LEN 10
#define swap(a,b) {typeof(a) t=a;a=b;b=t;}
// seq search
int seq_search(int* arr,int len,int key)
{
for(int i=0;i<len;i++)
{
if(key == arr[i]) return i;
}
return -1;
}
void sort(int *arr,int len)
{
for(int i=0;i<len-1;i++)
{
for(int j=i+1;j<len;j++)
{
if(arr[i] > arr[j])
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
void show(int* arr,int len)
{
for(int i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
//binary search
int binary_search(int* arr,int len,int key)
{
int l = 0,r=len-1;
while(l<=r)
{
int p = (l+r)/2;
if(arr[p] == key) return p;
if(key < arr[p]) r = p-1;
else l = p+1;
}
return -1;
}
int main(int argc,const char* argv[])
{
int arr[5] = {1,3,2,4,5};
printf("After sort\n");
sort(arr,5);
show(arr,5);
printf("seq_search for loc:%d\n",seq_search(arr,5,4));
printf("bin_search for loc:%d\n",binary_search(arr,5,4));
}
排序算法
排序算法的稳定性
在待排序的数据中,如果有值相同的数据,在排序的过程中如果不会改变它们的相对顺序,则认为排序算法为稳定的
2 1 0 2 5 -> 0 1 2 2 5 前后两个2的顺序不变则表示稳定
冒泡排序
对数据左右进行比较,把大的交换到最后,特点是对该算法对数据有序的敏感性,在排序的过程中发现有序可以立即停止,
如果待排序的数据基本有序,则冒泡排序的效率是非常高的。
时间复杂度:最优:O(n)平均 :O(n^2)
稳定性:稳定
选择排序
假定最开始的位置是最小值的下标,并记录该下标为min,然后与后面的数据进行比较,如果有比min位置的数据
更小的则更新min为更小的数据的下标,最后如果min的值发生了变化,则交换min位置的数据与最开始数据的位置,
虽然时间复杂度较高,但是数据交换的次数较少,因此实际运行的速度并不慢。选择是冒泡的一个变种,但是数据的
有序性不敏感,数据基本有序时冒泡快,数据较为混乱时选择快
时间复杂度:平均:O(n^2)
稳定性:不稳定 例如:10 10 1
插入排序
把数据看成两部分,一部分是有序的,剩余的数据逐个插入进去,当数据全部插入完成后,整个数据就是有序的
时间复杂度:O(n^2)
稳定性:稳定
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define LEN 10
#define swap(a,b) {typeof(a) t=a;a=b;b=t;}
//bubble sort
void bubble_sort(int* arr,size_t len)
{
//flag bit if finsh switch
bool flag = true;
for(int i=len-1;i>0 && flag;i--)
{
flag = false;
for(int j=0;j<i;j++)
{
if(arr[j] > arr[j+1])
{
swap(arr[j],arr[j+1]);
flag = true;
}
}
}
}
void show(int* arr,int len)
{
for(int i=0;i<len;printf("%02d ",arr[i++]));
}
// select sort
void select_sort(int* arr,size_t len)
{
for(int i=0;i<len-1;i++)
{
int min = i;
for(int j=i+1;j<len;j++)
{
if(arr[j] < arr[min]) min = j;
}
if(min != i) swap(arr[min],arr[i]);
}
}
// insert sort
void insert_sort(int* arr,size_t len)
{
for(int i=1,j=0;i<len;i++)
{
int val = arr[i];
for(j=i;j>0 && (arr[j-1] > val);j--)
{
arr[j] = arr[j-1];
}
if(j != i) arr[j] = val;
}
}
int main(int argc,const char* argv[])
{
int arr[LEN] = {};
for(int i=0;i<LEN;i++)
{
arr[i] = rand()%100;
}
printf("original sort :\n");
show(arr,LEN);
printf("\nbubble sort :\n");
bubble_sort(arr,LEN);
show(arr,LEN);
printf("\nselect sort:\n");
select_sort(arr,LEN);
show(arr,LEN);
printf("\ninsert sort:\n");
insert_sort(arr,LEN);
show(arr,LEN);
}