以头抢地之算法

本文详细介绍了基础算法中的几个关键概念,包括计算数组前缀和、高精度加法与乘法、二分查找法、快速排序和归并排序,以及删除重复元素的方法,展示了在编程中的实际应用。
摘要由CSDN通过智能技术生成

一、基础算法

1.前缀与拆分

PS:计算数组从l到r的项数和,即s[r]-s[l-1],s[n]为a[n]前n项和。

#include<stdio.h>
int main(){
	int a[7],s[7]={0};
	int l,r,i;//l,r代表从l到n,都大于1 且l<r 
	for( i=1;i<=6;i++)
		scanf("%d",&a[i]);
	scanf("%d %d",&l,&r);
	for( i=1;i<=6;i++) 
		s[i]=s[i-1]+a[i];
	for( i=1;i<=6;i++)
		printf("%d ",s[i]);
	printf("\n%d",s[r]-s[l-1]);
    return 0;
}

2.高精度加法

PS:定义三个字符数组a,b,分别用来存储两个加数,定义一个temp来存储进位,且初始化为0,定义一个整数数组存储和。
字符数组转换成整数数组A,B。
A[0]是个位,A[1]是十位,以此类推b(B数组也是如此)。
个位相加即A[0]+B[0]+temp(初始化为0不会影响)=C[0],如果有进位(和是两位数),则把进位(和的十位)存储在temp中,个位存储在C[0]。
十位相加即A[0]+B[0]+temp=C[0],如果有进位(和是两位数),则把进位(和的十位)存储在temp中,个位存储在C[0]。
一直加下去,得出结果。

#include <iostream>
#include <cstring>
using namespace std;
int A[100000],B[100000],C[10000000],temp=0,lena,lenb,lenc;
char a[1000000],b[10000000];//因为数组太大尽量都定义在main函数外面。 
int main(){
	cin>>a;
	cin>>b;
	lena=strlen(a) ;//计算长度 
	lenb=strlen(b);
	for(int i=0;i<lena;++i)
	A[i]=a[lena-1-i]-'0';
	/*
	将字符数组变成整数数组,并且将数组倒转。
	为什么要倒转呢?
	因为一开始输入时,高位在前,只有倒转以后才可以做到低位在前 。
	例如输入100,200;
	在a,b中存储时100,200;
	倒转以后在A,B中就时001,002;
	方便计算 
	*/ 
	for(int i=0;i<lenb;++i)
	B[i]=b[lenb-1-i]-'0';
	lenc=lena>lenb?lena:lenb;//得到较长的一个数
	for(int i=0;i<lenc;++i) 
	{
		C[i]=A[i]+B[i]+temp;
		temp=C[i]/10;
		C[i]%=10;
	}
	if(temp!=0)//看最后是否temp为0。并进行分类处理 
	{
	C[lenc]=temp;
	for(int i=lenc;i>=0;--i)
	cout<<C[i];
	return 0;
	}
	for(int i=lenc-1;i>=0;--i)//先输出高位 c
	cout<<C[i];
	return 0;
}

3.高精度乘法

PS:

分析c数组下标的变化规律,可以写出如下关系式:ci = c’i +c”i +…由此可见,c i跟a[i]*b[j]乘积有关,跟上次的进位有关,还跟原c i的值有关,分析下标规律,有

c[i+j-1]= a[i]*b[j]+ x + c[i+j-1]; 
​
x=c[i+j-1]/10 ; 
​
c[i+j-1]%=10;
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int main()
{
    char a1[100],b1[100];
    int a[100],b[100],c[100],lena,lenb,lenc,i,j,x;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    memset(c,0,sizeof(c));
    gets(a1);gets(b1);
    lena=strlen(a1);lenb=strlen(b1);
    for (i=0;i<=lena-1;i++) a[lena-i]=a1[i]-48;
    for (i=0;i<=lenb-1;i++) b[lenb-i]=b1[i]-48;
  	for (i=1;i<=lena;i++)
	{
	     x=0;                                               //用于存放进位
	     for (j=1;j<=lenb;j++)                     //对乘数的每一位进行处理
	     {
		   c[i+j-1]=a[i]*b[j]+x+c[i+j-1]; //当前乘积+上次乘积进位+原数	    	   x=c[i+j-1]/10;
		   c[i+j-1] %= 10;
	     }
	     c[i+lenb]=x;                                  //进位
	}
	lenc=lena+lenb;
	while (c[lenc]==0&&lenc>1)       //删除前导0
		lenc--;
	for (i=lenc;i>=1;i--)
		cout<<c[i];
	cout<<endl;
	return 0;
}

4.二分查找法

PS:二分法最重要的两个点,就是循环条件和后续的区间赋值问题。以下是左闭右闭型。

左闭右开则相反。

int search(int nums[], int size, int target) //nums是数组,size是数组的大小,target是需要查找的值
{
    int left = 0;
    int right = size - 1;	// 定义了target在左闭右闭的区间内,[left, right]
    while (left <= right) {	//当left == right时,区间[left, right]仍然有效
        int middle = left + ((right - left) / 2);//等同于 (left + right) / 2,防止溢出
        if (nums[middle] > target) {
            right = middle - 1;	//target在左区间,所以[left, middle - 1]
        } else if (nums[middle] < target) {
            left = middle + 1;	//target在右区间,所以[middle + 1, right]
        } else {	//既不在左边,也不在右边,那就是找到答案了
            return middle;
        }
    }
    //没有找到目标值
    return -1;
}

5.快速排序法

原理:

先选择一个数作为 基准值 (这里用的是 第一个数),进行一次排序
然后将所有比'基准值小的数'放在基准值的'左边',
将所有比'基准值大的数'放在基准值的'右边',

然后再对两边的,各自'再取一个数作为基准值',然后再次排序递归[自己调自己])。

思想:

通过一个基准值,把一组数据分成两个部分(一边小,一边大),然后,在对两个部分,分别找一个基准值再次进行排序直至每一个小部分不可再分,所得到的整个数组就成为了有序数组。

#include <stdio.h>
#include <stdlib.h>
 
#define  N  10
 
//快速排序法
int quick_sort(int *a, int low, int high)
{
	int i = low;	//第一位
	int j = high;	//最后一位
	int key = a[i]; //将第一个数作为基准值-- 先找到一个基准值
 
	//进行排序---> 最终结果就是 左面的 都比基准值小 ,右面的都比 基准值大,所以这是所有循环的结束条件
	while (i < j)
	{
		//下面的循环执行的条件是 如果右面的比基准值大,就赋一下值,否则继续向前移动
                //---如果直接把循环写成下面这样---
		//while(a[j] >= key) //如果下面的不写这个i<j,这个就出错、越界,并且排序不准--理由:
		//如果i<j,并且: 右面的值 大于 基准值 时,j往前移动一个
					//i 跟 j 的可能情况 只有 i<j i==j
		while(i < j && a[j] >= key)//i<j 是 当前while循环的结束条件,如果没有这个,i会大于j,出现越界,错误 
		{
			j--;//继续走
		}//如果不成立,也就是 a[j] <= key;右面的比key小了,那就换个位置
		//把a[j]的数据给a[i]	
		a[i] = a[j];	
 
		//将事先保存好的基准值与左边的值进行比较,如果基准值大,保持不变,i往前
		//然后 判断一下这个新的a[i],也就是之前的a[j]跟key值的关系---> 一定是 a[i]<key
		//所以把i向前移动一下,i++
		while(i < j && a[i] <= key)
		{
			i++;
		}
		//移动完以后,把新的位置的a[i]的数值 给刚才的 a[j],然后开始下一次循环
		a[j] = a[i];
	}
 
	//跳出循环,将基准值放入数据a[i]中
	a[i] = key;
	//对基准值左边 的所有数据 再次进行快速查找(递归)
	if (i-1 > low) 
	{
		quick_sort(a, low, i-1);
	}
 
	//对基准值右边的所有数据再次进行快速查找(递归)
	if (i+1 < high)
	{
		quick_sort(a, i+1, high);
	}
 
	return 0;
} 
 
int main(int argc, const char *argv[])
{
	int a[N] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 0};//先整了个数组,初始化了一堆数	
 
	int i = 0;
	printf("排序前:\n");
	for(i = 0; i < N; i++)
	{
		printf("%d ", a[i]);
	}
	putchar(10);
 
	//调用-快排
	quick_sort(a, 0, N-1);//数组,0 ,9
														
	printf("排序后:\n");
	for(i = 0; i < N; i++)
	{
		printf("%d ", a[i]);
	}
	putchar(10);
	
	return 0;
}

6.归并排序法

算法思路:归并排序算法有两个基本的操作,一个是分,也就是把原数组划分成两个子数组的过程。另一个是治,它将两个有序数组合并成一个更大的有序数组。

第一步,将待排序的线性表不断地切分成若干个子表,直到每个子表只包含一个元素,这时,可以认为只包含一个元素的子表是有序表。
第二步,将子表两两合并,每合并一次,就会产生一个新的且更长的有序表,重复这一步骤,直到最后只剩下一个子表,这个子表就是排好序的线性表。

void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex){
    int i = startIndex, j=midIndex+1, k = startIndex;
    while(i!=midIndex+1 && j!=endIndex+1) {
        if(sourceArr[i] > sourceArr[j])
            tempArr[k++] = sourceArr[j++];
        else
            tempArr[k++] = sourceArr[i++];
    }
    while(i != midIndex+1)
        tempArr[k++] = sourceArr[i++];
    while(j != endIndex+1)
        tempArr[k++] = sourceArr[j++];
    for(i=startIndex; i<=endIndex; i++)
        sourceArr[i] = tempArr[i];
}
 
//内部使用递归
void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex) {
    int midIndex;
    if(startIndex < endIndex) {
        midIndex = startIndex + (endIndex-startIndex) / 2;//避免溢出int
        MergeSort(sourceArr, tempArr, startIndex, midIndex);
        MergeSort(sourceArr, tempArr, midIndex+1, endIndex);
        Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
    }
}
 
int main(int argc, char * argv[]) {
    int a[8] = {50, 10, 20, 30, 70, 40, 80, 60};
    int i, b[8];
    MergeSort(a, b, 0, 7);
    for(i=0; i<8; i++)
        printf("%d ", a[i]);
    printf("\n");
    return 0;
}

7.删除重复元素

算法思想:
等同于设置快慢指针,快指针寻找与慢指针所指元素不等的元素,慢指针扫描整个顺序表,一旦找到不相等的元素,慢指针就向前走一步,并且赋值为快指针所指向元素。这样就可以保证, 慢指针每向前走一步所被赋值的元素都是不重复的,一遍下来,就可以删除所有重复的元素。

void DeleteSimple(SeqList &L){
	int i,j;
	for(i=0, j=1; j<L.length; j++)
		if(L.data[i]!=L.data[j])
			L.data[++i] = L.data[j];
	L.length = i+1;
}

 

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值