蓝桥第二讲:基础数据结构

(1)高精度加法:

遗漏知识点:

1.求字符串长度函数:#include<string.h> strlen(字符串名字)

2.字符串名字:printf("%s\n",a)

3.FOR循环语法:!!!!!!,中间是判断通过条件!!!!!!!!!

易错点:

1.大数用字符型存储,涉及到整数型的运算要记得转换。

2.加法中,缺位,补位等问题的解决。两数相加要考虑进位和缺位这两个数,和每一位的控制。

答案:

#include<stdio.h>
#include<string.h> 
#include <stdlib.h>
int main(int argc, char *argv[])
{
	char a[110],b[110];
	int aaa[110],bbb[110],ccc[110];
	int i,j,A,B,s=0,n=0;
	scanf("%s",a);
	scanf("%s",b);
	/*printf("%s\n",a);
	printf("%s",b);*/
	A=strlen(a);
	B=strlen(b);
	/*printf("%d\n",A);
	printf("%d",B);*/
	for(i=A-1;i>=0;i--) aaa[i]=a[i]-'0';
	for(i=B-1;i>=0;i--) bbb[i]=b[i]-'0';
	
	for(i=A-1,j=B-1;i>=0||j>=0||s>0;i--)
	{
		//缺位 
		if(i>=0) s=s+aaa[i];
		if(j>=0) s=s+bbb[j];
		//存结果,从后向前 
		ccc[n]=s%10;
		//进位 
		s=s/10; 
		j--;n++;
	}
	for(i=n-1;i>=0;i--)printf("%d",ccc[i]);
	return 0;
}

(2)回形取数

知识点:

1.!!!!SCANF()里面放地址啊啊!!

易错点:

<思维简化>----两个数组+大循环(四个小循环不用复杂的约束)+大循环次数向上取整
1.矩阵数组避免C语言数组坐标问题,输入注意坐标:

for(i=1;i<=n;i++)				//输入坐标归正 
    for(j=1;j<=m;j++)
      scanf("%d",&st[i][j]);

答案:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  int m,n;					
  scanf("%d%d",&m,&n);
  int i,j;
  int a[210][210],r[210][210];			//输入 
  
  for(i=1;i<=m;i++){				//数组坐标简化 
  	for(j=1;j<=n;j++){
  		scanf("%d",&a[i][j]);
	  }
  }
  
  
  int q=1,num=(n+1)/2;		//q记循环圈数,num记大循环限制 
   
  for(q=1;q<=num;q++)				//大循环 
  {
  	
	for(i=q;i<=m+1-q;i++)		//1
	{
	if(r[i][q]==0){
		printf("%d ",a[i][q]);
		r[i][q]=1;
	}
	}
  	for(j=q;j<=n+1-q;j++){		//2
	if(r[m-q+1][j]==0){
		printf("%d ",a[m-q+1][j]);
		r[m-q+1][j]=1;
	}
	}
  	for(i=m-q+1;i>=q;i--){				//3
	if(r[i][n-q+1]==0){
		printf("%d ",a[i][n-q+1]);
		r[i][n-q+1]=1;
	}				
	}
  	for(j=n-q+1;j>q;j--){					//4
	  if(r[q][j]==0){
		printf("%d ",a[q][j]);
		r[q][j]=1;
	}		
	}
  }
  return 0;
}

静态链表:

const int N = 10000;                   //按需要定义静态链表的空间大小
struct node{                           //单向链表
    int id;                            //这个结点的id
    int data;                          //数据
    int nextid;                        //指向下一个结点的id
}nodes[N];                             //静态分配需要定义在全局

//为链表的next指针赋初值,例如:
    nodes[0].nextid = 1;
    for(int i = 1; i <= n; i++){
        nodes[i].id = i;     //把第i个结点的id就赋值为i
        nodes[i].nextid = i + 1;   //next指针指向下一个结点
    }

//定义为循环链表:尾指向头
    nodes[n].nextid = 1;                 

//遍历链表,沿着nextid访问结点即可

//删除结点。设当前位于位置now,删除这个结点  
    nodes[prev].nextid = nodes[now].nextid;   //跳过结点now,即删除now
    now = nodes[prev].nextid;                 //更新now

双向静态链表:

const int N = 10000;
struct node{                          //双向链表
    int id;                           //结点编号
    int data;                         //数据
    int preid;                        //前一个结点
    int nextid;                       //后一个结点
}nodes[N];

//为结点的指针赋初值,例如
    nodes[0].nextid = 1;  
    nodes[1].preid  = 0;
    for(int i = 1; i <= n; i++){       //建立链表
        nodes[i].id = i;
        nodes[i].preid  = i-1;          //前结点
        nodes[i].nextid = i+1;          //后结点
    }
//定义为循环链表
    nodes[n].nextid = 1;               //循环链表:尾指向头
    nodes[1].preid = n;                //循环链表:头指向尾

//遍历链表,沿着preid和nextid访问结点即可

//删除结点。设当前位于位置now,删除这个结点
    prev = nodes[now].preid;   
    next = nodes[now].nextid;
    nodes[prev].nextid = nodes[now].nextid;  //删除now
    nodes[next].preid  = nodes[now].preid;   
    now = next;                              //更新now

//插入结点,见后面的习题“自行车停放”

(3)自行车停放:

易错点:

1.链表重学一遍,全忘了

这个题的思想是:先填充数据,记录位置索引(方便搜索),先连尾,后连头

 答案:

#include<stdio.h>
#include<stdlib.h> 
const int N = 100000;
struct node{
	int data;
	int preid;
	int nextid; 
}nodes[N];
int locate[N];
int now;

void initNodes()
{
	nodes[0].nextid=1;
	nodes[1].preid=0;
	now=2;
}

void insert(int k,int x) //k是此时插入的节点的前一个节点序号 
{
	nodes[now].data = x;
	
	locate[x] = now;
	
	nodes[now].nextid = nodes[k].nextid;
	nodes[nodes[k].nextid].preid=now;
	
	nodes[now].preid = k;
	nodes[k].nextid = now;
	
	now ++; 
}

int main(int argc, char *argv[])
{
	int n,x,y,z;
	scanf("%d",&n);
	initNodes(); 
	scanf("%d",&x);
	insert(0,x);
	n--;
	while(n--)
	{
		scanf("%d%d%d",&x,&y,&z);
		if(z == 0) insert(nodes[locate[y]].preid,x);
		else if(z == 1) insert(locate[y],x);
	}
	
	for(int i=nodes[0].nextid;i!=1;i=nodes[i].nextid)
	printf("%d ",nodes[i].data);
	
	return 0;
}

(4)队列操作:

知识点:

(1)有关队列:

队列:先进先出,插入的那端称为队尾(入队),删除的那段称为队头(出队)。

顺序队列:数组+两个指针(front指向队头元素,rear指向队尾元素) ——————>假溢出问题

循环队列(解决假溢出):使用队列首尾相连接的顺序结构(不会用出队)

//队空的条件
q.front == q.rear;
//队满的条件
(q.rear+1)%maxsize == q.front
//入队时队尾的移动
rear=(rear+1)%M;
//出队时队头的移动
front=(front+1)%M;

(2)->:

结构体指针类型的变量可以用->指向成员变量

(3)switch分支结构:

 (4)指针分配空间:malloc()函数

需要调用#include<malloc.h>

答案:

#include<stdio.h> 
#include<stdlib.h>
#include<malloc.h>
const int N = 50; 
typedef struct{
	int *data;
	int front;
	int rear;
}Queue;
Queue Q;

int initQuene()			//初始化 
{
	Q.data = (int *)malloc(sizeof(int));
	if(!Q.data) exit(0);
	Q.front=Q.rear=0;
	return 1; 
}

void QueneNum(int n)		//求队列长度 
{
	printf("%d\n",(Q.rear-Q.front+n)%n);
} 

int EnQuene(int x,int n)		//入队
{
	if((Q.rear+1)%n==Q.front){		//队列满 
		return -1; 
	}
	Q.data[Q.rear]=x;
	Q.rear=(Q.rear+1)%n;
	return 1;
} 

int DeQuene(int n)		//出队
{
	if(Q.rear==Q.front){				//队列空 
		printf("no");return -1; 
	}
	printf("%d\n",Q.data[Q.front]);
	Q.front=(Q.front+1)%n;
	return 1;
} 

int main(int argc,char *argv)
{
	int n;
	scanf("%d",&n);		//队列长度
	int stop = initQuene();
	int m,x;
	while(stop>0){
		scanf("%d",&m);		//命令 
		switch(m) 
		{
		case 1:scanf("%d",&x);stop=EnQuene(x,n);break;
		case 2:stop=DeQuene(n);break;
		case 3:QueneNum(n);stop=1;break;
		}
	}
	return 0;
}

(5) 栈练习题:汉诺塔

知识点:

(1)栈:(水桶)后进先出

只能在栈顶(top)进行插入和删除操作;

顺序栈:数组+栈顶(top)+栈底(base)

top指针实际指的是栈顶元素的上一个元素

const int N = 1000;
typedef struct{
    int *top;        //栈顶指针
    int *base;       //栈底指针
    int stacksize;        //栈的实际长度
}SqStack;

a.初始化

int intStack(SqStack &S)
{
    //(1)为顺序栈分配一个最大容量为N的数组空间
    S.base = (int *)malloc(N*sizeof(int));
    if(!base) exit(0);
    //(2)栈顶指针top初始化为base,表示栈为空
    S.top=S.base;
    //(3)设置栈的最大容量MAXSIZE
    S.stacksize = N;
    return 1;
}

b.入栈

int Push(SqStack &S,int x)
{
    //(1)判断栈是否满
    if(s.top-s.base == s.size) return 0;
    //(2)压栈:先赋值,再上移
    *S.top++=e;
    return 0;
}

c.出栈

int Pop(SqStack &S)
{
    //(1)判断栈是否为空
    if(S.base == S.top) return 0;
    //(2) 出栈
    *S.top--;
    return 1;
}

(2)汉诺塔算法理解:(递归)

问题实质:(递归问题)

(1)先把n以上的n-1个盘子从A杆子移到B杆子,以C为中介杆子(限制条件:n-1=1;n=2)

(2)把n盘子从A杆子移到C杆子

  (3)剩下的n-1个盘子再重复以上两个动作

答案:

#include<stdio.h>
#include<stdlib.h> 
int count=0;
int n,m;
void move(int n,char a,char b)
{
	count++;
	if(count == m){
		printf("#%d: %c->%c\n",n,a,b);
	}
}
void Hanoi(int n,char x,char y,char z)
{
	if(n>1)
	{
		Hanoi(n-1,x,z,y);
		move(n,x,z);
		Hanoi(n-1,y,x,z);
	}
	else
	move(n,x,z);
}
int main(int argc,char *argv[])
{
	scanf("%d%d",&n,&m);
	Hanoi(n,'A','B','C');
	printf("%d",count); 
	return 0;
}

(6)二叉树练习题:FBI树

知识点:

(1)二叉树:

树:(1)有且只有一个根(2)除根节点之外,其余节点他们自成一棵树

二叉树:(1)有且只有一个根(2)除根节点外,其余节点分为两个互不相交的子集,分别称为根的左子树和右子树。

二叉树与树的区别:(1)每个节点最多两颗子树(2)子树有左右之分

二叉树的链式存储:(二叉链表)

a.二叉链表的存储表示

typedef strcut BiTNode{
        TElemType data;
        struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

b,遍历二叉树(递归)

先序遍历:(1)访问根节点  (2)先序遍历左子树 (3)先序遍历右子树

中序遍历:左子树-.>根节点->右子树

后序遍历:左子树->右子树->根节点

void InOrderTraverse(BiTreee T)
{
    if(T)            //若二叉树非空
    {
        InOrderTraverse(T->lchild);
        cout<< T->data;            //访问根节点
        InOrderTraverse(T->rchild);
    }
}

c.建立二叉链表

void CreateBiTree(BiTree &T)
{
    //(1)读入字符ch
    scanf("%c",&ch);
    //(2)若ch为‘#’,则二叉树为空树
    if(ch=='#") T=NULL;
    else
    {
    //申请一个结点空间T
    T=(char)malloc(sizeod(char));
    //将ch赋给T->data
    T->data = ch;
    //递归创建T的左子树
    CreateBiTree(T->lchild);
    //递归创建T的右子树
    CreateBiTree(T->rchild);
}

d.计算二叉树的深度

int Depth(BiTree T)
{
    if(T==NULL) return 0;    //如果是空树,深度为0,递归结束
    else
    {
    m=Depth(T->lchild);        //递归计算左子树的深度
    n=Depth(T->lchild);        //递归计算右子树的深度
    if(m>n) return (m+1);
    else return (n+1);
    }
}

e.统计二叉树中节点的个数

int NodeCount(BiTree T)
{
    if(T == NULL) return 0;
    else return NodeCount(T->lchild)+NodeCount(T->rchild)+1;
}

2. C++ 1<<n

将左数的二进制编码想左移动n位并将空位补0

 题意理解:

答案:

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
void FBI(char num[], int sum)
{
	if (sum == 1)
	{
		if (num[0] == '0')
			cout << "B";
		else
			cout << "I";
	}
	else
	{
		char num1[2000];
		char num2[2000];
		for (int i = 0; i < sum / 2; i++)
		{
			num1[i] = num[i];
			num2[i] = num[i + (sum / 2)];
		}
		FBI(num1, sum / 2);
		FBI(num2, sum / 2);
		bool isF = false;
		for (int i = 0; i < sum-1; i++)
		{
			if (num[i] != num[i + 1])
			{
				isF = true;
				break;
			}
		}
		if (isF == true)
		{
			cout << "F";
		}
		else
		{
			if (num[0] == '0')
				cout << "B";
			else
				cout << "I";
		}
	}
}
int main()
{
	int n;
	cin >> n;
	char num[2000];
	int sum = pow(2, n);
	for (int i = 0; i < sum; i++)
	{
		cin >> num[i];
	}
	FBI(num, sum);
	return 0;
}

(7)蓝桥杯真题:完全二叉树的权值(2019 年省赛)(留着)

知识点:

(1)完全二叉树:深度为K的,有n个节点的二叉树,当且仅当其每一个节点都与深度为k的满二叉树中编号从1至n的节点一一对应时,称之为完全二叉树。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值