算法基础(基础知识)

1.题1:7744问题
输出所有形如aabb的4位完全平方数(即前两位数字相等,后两位数字也相等)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
int main()
{
    for(int a =1;a<=9;a++)
    {
        for(int b=1;b<=9;b++)
        {
            int n=a*1100+b*11;
            int m=floor(sqrt(n)+0.5);
            if(m*m==n)
            {
                printf("%d\n",n);
            }
        }
    }
    return 0;
}

这里说明几点:
1.floor的函数作用是用来返回不超过x的最大整数
2.+0.5是用来调整计算器的误差
算法分析:
可以先求出其平方根,然后看它是否为整数,即用一个int型变量m存储sqrt(n)四舍五
入后的整数,然后判断m2是否等于n。函数floor(x)返回不超过x的最大整数。
快速排序

//快速排序
//快速排序的算法思路是:在一组数据中,选择一个基准数,将小于这个基准数的数排到这个基准数之后,
//基准数一般采用的是数组的第一位即left位,最终位为right位,最终达到完全排序的方法
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
int a[10]={1,8,9,7,6,5,4,16,15,16},n;
void quicksoft(int left,int right)
{
    int i,j,t,temp;
    if(left>right) return ;
    temp=a[left];//temp用来存储基准数
    i=left;j=right;//左侧开始巡逻数,右侧开始巡逻数
    while(i!=j)
    {
        //顺序是从左向右找,不用for的原因是结束条件非常特殊,用while比较合适
        while(a[j]>=temp&&i<j)//这个判断条件意味着即没有左右两个巡逻数相遇,而且找到了一个数大于基准数
        {
            j--;
        }//再从左向右找
        while(a[i]<=temp&&i<j)
        {
            i++;
        }
        //下一步是交换两个数在数组中的位置
        if(i<j)//当两个巡逻数没有相遇的时候
        {
            t=a[i];
            a[i]=a[j];
            a[j]=t;
        }
    }
    //最终将基准数归位
    a[left]=a[i];
    a[i]=temp;
    //一次快速排序完成,要完成更多的数,那么进行更多次的快速排序,即递归
    quicksoft(left,i-1);
    quicksoft(i+1,right);
    return;
}
int main()
{
    /*for(i=0;i<10;i++)//有读入十个数据
    {
        scanf("%d",&a[i]);
    }
    测试用数据
    */
    quicksoft(0,9);//输入的是数组的下标,根据输入的下标的不同而有差异
    for(int i=0;i<10;i++)
    {
        printf("%d ",a[i]);
    }
    return 0;
}

一.队列

//队列,用队列和解密的法则来理解链表
//原数字串未知,但知道进行这种加密规则之后的字符串
//加密规则:首先将第一个数删除,接着将第二个数放到这串数的末尾,
//接着将第三个数删除,在第四个数放到这串数的末尾,以此类推
//那么,可以简单地理解为,向头字符串取两个元素,排在前头的元素闪掉,后面那一个元素放到字符串的末尾
//直到检索到最后一个元素,将最后那个元素删除,按照刚才删除的顺序把他们链接起来,并放到字符串的最前面
//6 1 5 9 4 7 2 8 3
//1 2 3 4 5 6 7 8 9
//如果现在给出的是6 3 1 7 5 8 9 2 4
//前n/2个元素比较好确认,那么剩余的就要开始模拟
//解密过程如下:
//1:1 7 5 8 9 2 4 3(1)
//2:5 8 9 2 4 3 7(5)
//3:9 2 4 3 7 8(9)
//4:4 3 7 8 2(4)
//5:7 8 2 3(7)
//6:2 3 8(2)
//7:8 3(8)
//(3)
/*算法诠释:删除数的过程我们可以理解为:将所有后面的数都往前面挪动一位,将前面的数覆盖
**具体实现:引入两个变量,一个变量用来记录首位,另一个用来记录末尾(即队列的最后一位)
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<ctype.h>
int main()
{
  int a[101]={0,6,3,1,7,5,8,9,2,4},head,tail;
  //初始队列
  head=1,tail=10;//初步给定队列,tail是最后一位下标+1,避免数据的丢失
  while(head<tail)//循环检索
  {
      printf("%d",a[head]);
      head++;
      a[tail]=a[head];
      tail++;
      head++;
  }
  return 0;
}

在此总结一下,队列是一种特殊的线性结构它只允许在队列的首部,进行删除操作,这时候称之为出队,而在队列的尾部进行插入操作,这时称之为入队,当队列中没有元素的时候(即head==tail)的时候,称为空队列。越是靠前的元素就越能早的完成出队操作,这种称之为先进先出原则。
下面继续详细地讲述队列,队列有三个基本元素,(一个数组,两个变量),头变量完成出队操作,尾变量完成入队操作,数组用于存储数据和保持排序。
我们可以将其定义为一个结构体。

  struct queue
  {
    int data[1000];//队列的主体
    int head;//队首
    int tail;//队尾
  };
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<ctype.h>
struct queue
{
     int data[100];
     int head;
     int tail;
};
int main()
{
  struct queue q;
  int i;
  q.head=1;
  q.tail=10;
  for(i=1;i<=10;i++)
  {
       scanf("%d",&q.data[i]);
  }
  while(q.head<q.tail)
  {
       printf("%d",q.data[q.head]);
       q.head++;
       q.data[q.tail]=q.data[q.head];
       q.head++;
       q.tail++;
  }
  return 0;
}

二.栈
栈是一种后进先出的数据结构,栈限定为只能够在栈的一端进行插入和删除操作,类似的情形参见汉诺塔问题。
下面是具体的实现与讲解:
栈的实现需要一维数组和一个指向栈顶的变量,对这个变量进行操作即可。通过栈可以对经典的回文串问题进行求解。
题解:如果一个字符串时回文串的话,那么它必定是中间对称的,我们需要求解这个回文串的中点.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <string.h>
//利用栈的特性,对一串字符串进行输入和判别
//但是我们只需要对中点之前的入栈,对中点之后的进行判别,如此即可判断出是否是回文串
int main()
{
    char a[101]="",s[101]="";
    int top=0,i;
    gets(a);
    int len=strlen(a);
    int mid=len/2-1;
    for(i=0;i<=mid;i++)
    {
        s[++top]=a[i];
    }
    int len_next;
    if(len%2==0)//特别要注意的是len长度的正负性,会影响到我们一一匹配的正确性.
    {
        len_next=mid+1;
    }
    else
    {
        len_next=mid+2;
    }
    for(i=len_next;i<=len-1;i++)
    {
        if(a[i]!=s[top])
        {
            break;
        }
        top--;
    }
    if(top==0)//如果最终TOP的值是0,那么证明整个过程都不存在不匹配的字符.
    {
        printf("YES");
    }
    else printf("NO");
    return 0;
}

三.可变数组与链表

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
int BLOCKS_SIZE=20;

typedef struct
{
    int *array;//表示一个数组的首地址,当不够用的时候,我们可以利用指针的特性来使得数组变大
    int size;
}Array;
//链表的存在相当于一个可变数组,同样是用来存储数据,这里我们使用数组来模拟链表的实现
//可变数组的实现包括:
//1.可变数组的创建
//2.可变数组的访问
//3.可变数组的内存释放
//首先声明这几个函数
Array array_create(int intsize);//传入的是需要的大小,进行一个动态分配的操作
void array_free(Array *a);//传入需要free掉的内存地址
int array_size(const Array *a);//要得到的是需要的内存大小
int* array_at(Array *a,int index);
void array_flate(Array *a,int more_size);
/*typedef struct
{
    int *array;//表示一个数组的首地址,当不够用的时候,我们可以利用指针的特性来使得数组变大
    int size;
}Array;//表示的是用Array这个变量名来指代一整个可变的数组
1.可变数组的创建
*/
Array array_create(int intsize)
{
    Array a;
    a.array=(int*)malloc(sizeof(int)*intsize);
    a.size=intsize;
    return a;//创建完毕直接返回对应的数组,这个返回值包括一个地址和一个已经动态分配好的数组空间
}

void array_free(Array *a)
{
    free(a->array);
    a->array=NULL;
    a->size=0;
}

int array_size(const Array *a)
{
    return a->size;
}

int* array_at(Array *a,int index)//传回的是数组中对应元素的地址,即实现了访问数组中的元素的功能
{
    if(index>=a->size)
    {
        array_flate(a,((index/BLOCKS_SIZE)+1)*BLOCKS_SIZE-a->size);
        //说明一下这个公式,index/BLOCKS_SIZE==下标所在的那第几个模块,比如21就位于第2个模块中
        //接着发现内存空间不够,开始申请,需要更多的空间是2*20-原本的数组长度=需要更多的长度
        //需要的长度与模块长度和原数组长度有关。
    }
    return (&(a->array[index]));
}

void array_flate(Array *a,int more_size)//按照moresize的值扩大数组
{
    int *p=(int*)malloc((sizeof(int))*(a->size+more_size));//此处申请一块新的空间
    for(int i=0;i<a->size;i++)
    {
        p[i]=a->array[i];
    }
    free(a->array);
    a->array=p;
    a->size=a->size+more_size;
}

int main(void)
{
    Array a=array_create(100);
    printf("%d\n",array_size(&a));
    *array_at(&a,0)=10;
    printf("%d\n",a.array[0]);
    int number=0,count=0;
    while(number!=-1)
    {
        scanf("%d",&number);
        if(number!=-1)
        {
            *array_at(&a,count)=number;
            count++;
        }
    }
    array_free(&a);
    return 0;
}

可变数组的缺点在于,每当需要扩大数组的容量的时候,往往再次申请一个很大的变量空间,而这在单片机(小内存存储设备)上的程序设计是不现实的,所以我们需要实现内存的最大利用化,当一个数组用完,能否找到一个方法,把上一个数组,和下一个数组连接起来呢?
链表的实现和基本操作
1.申请空间的说明

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
//基本的操作
//int *p;定义一个指针型的变量
//p=(int *)malloc(sizeof(int)申请一个空间来指向对应的变量
//因为malloc对应的是*void 类型表示的是未定型的指针,所以这里要指定一个我们想要的指针类型来申请空间
//指针的类型

链表中的每一个节点都由两部分组成,分为数据域和指针域,,而指针域通常是用来存放下一个结点的地址,可以用指针来实现。

//结点的定义
struct node
{
    int data;
    struct node *next;//表示指向下一个结构体的指针,用来存放地址。 
    //这里说明一下,由于下一个结点也是一个结构体,所以我们定义的时候也要定一个结构体类型的指针
};

建立链表
1.关于头结点:对于头结点,我们需要在一开始将其初始化head=NULL,表示指向空节点。

struct node *head;
head=NULL;

2.临时结点(又被认为是新增结点)

struct node *p;
//动态申请一个空间,用来存放新增结点,并用临时指针p指向这个节点
p=(struct node*)malloc(sizeof(struct node));

读入数据

int a;
scanf("%d",&a);
p->data=a;//将数据存储到当前结点的数据域中去
p->next=NULL;//设置当前结点的后续指针向空,表示下一个结点还是空的

3.结点在创建时,指针的指向问题。

if(head==NULL)//表示表还是空的时候
{
    head=p;//表示头结点是p,新增一个p结点
}
else
{
    //如果不是第一次创建的结点,那么需要:
    q->next=p;//表示上一次结点的后指针要指向当前结点。
}
q=p;
//最后要将指针q也指向单签结点,因为待会儿临时指针p将会指向新创建的结点
//其实就是一个准备工作,数据已经存好了,如果待会有新的数据要进来,那么就需要新的结点,而新的结点是需要换字母表示的(你懂我意思把)

连续实现如下:

int main()
{
    struct node *head,*p,*q,*t;
    int i,a,n;
    scanf("%d",&n);//表示你要读入几个数
    head=NULL;
    for(i=0;i<n;i++)
    {
        scanf("%d",&a);
        //读入数据后先创建(申请空间)给数据存放
        p=(struct node*)malloc(sizeof(struct node));
        p->data=a;
        p->next=NULL;
        if(head==NULL)
        {
            head=p;
        }
        else
        {
            q->next=p;
        }
        q=p;
    }
    //完毕
    t=head;//接着尝试读取这些数据并且输出
    while(t!=NULL)
    {
        printf("%d ",t->data);
        t=t->next;//链表中最常用的遍历方式
    }
    //临时指针作为一个指向标的作用 
}

链表的插入操作

    //如果我们想要在这个有序地数组中插入某个数据,该怎么办呢?
    t=head;//准备遍历这个链表
    scanf("%d",&a);
    while(t!=NULL)
    {
        if(t->next==NULL||t->next->data>a)//表示的是这个节点虽然不大于a但是下一个大于a,要注意指向关系
            //或者是直接遍历完了所有的数据都没有发现符合条件的节点,那么就直接放到最后即可
        {
            p=(struct node*)malloc(sizeof(struct node));
            p->data=a;
            p->next=t->next;
            t->next=p;
            break;
        }
        t=t->next;
    }
    t=head;
    while(t!=NULL)
    {
        printf("%d ",t->data);
        t=t->next;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值