24-1-30学习总结

学习小结

链表

对于链表的学习,首先要大体对指针和结构体有一定的认识。

链表使用时一般先用结构体定义一下,一般包括两部分 数据域和指针域 ,数据域顾名思义就是储存数据的,指针域是储存指向下一个结构的指针,如下

typedef struct SListNode
{
	int data;
	struct SListNode* next;
}SLND;

 这两种看起来是有一些不同的,但是第一种主要是方便后面的定义(我个人喜欢第一个)。具体区别可以先学一下结构体就明白了。

struct SListNode
{
	int data;
	struct SListNode* next;
};

准备工作做好了接下来就是对链表进行操作了。

第一步:肯定是要初始化!!!!(也可以说是搭建结点)

//建立结点
SLND* CreateSListNode(int x)
{
	SLND* NewNode = (SLND*)malloc(sizeof(SLND));
	NewNode->data = x;
	NewNode->next = NULL;
	return NewNode;
}

第二步:搭好结点了就可以准备把这些结点穿起来 。(也可以说是在每个结点的结尾插入结点)

//尾插结点
void SListPushBack(SLND** head, int x)
{
	SLND* New = CreateSListNode(x);
	if (*head == NULL)
		*head = New;
	else
	{
		SLND* t = *head;
		while (t->next != NULL)
			t = t->next;
		t->next = New;
	}
}

这样一个简单的链表就搭起来了,但是通常解题的时候不会这么简单 ,(会用各种条件限制)

所以现在说一下几个小方法

头插节点(比如说开头忘了加一个结点)

//头插节点
void SListPushFront(SLND** head, int x)
{
	SLND* New = CreateSListNode(x);
	New->next = *head;
	*head = New;
}

尾删结点(结尾的结点用不到了,就需要删掉,防止野指针的出现,出现危险)

一定一定一定注意把结尾的指针释放掉(用free函数)因为野指针真的很危险!!!!

//尾删结点
void SListPopBack(SLND** head)
{
	//没有结点,空链表
	if (*head == NULL)
	{
		return;
	}
	//只有一个结点
	else if ((*head)->next == NULL)
	{
		free(*head);
		*head = NULL;
	}
	//多个结点
	else
	{
		SLND* prev = NULL;
		SLND* t = *head;
		while (t->next != NULL)
		{
			prev = t;            //找到倒数第二个结点的指针
			t = t->next;
		}
		free(t);                  //释放最后一个结点
		prev->next = NULL;        //将倒数第二个指针置空,防止成为野指针
	}
}

 头删结点

//头删结点
void SListPopFront(SLND** head)
{
	if (*head == NULL)
		return;
	else
	{
		SLND* next = NULL;
		next = (*head)->next;
		free(*head);
		*head = next;
	}
}

 下面是用完整是代码实现插入结点

typedef struct node
{
	int data;
	struct node* next;
}Nd;
int main()
{
	Nd* p = NULL, * q = NULL, * head = NULL, * t = NULL;
	int n = 0, a = 0;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &a);
		p = (Nd*)malloc(sizeof(Nd));
		p->data = a;
		p->next = NULL;
		if (head == NULL)
			head = p;
		else
			q->next = p;
		q = p;
	}
	scanf("%d", &a);
	t = head;
	while (t != NULL)
	{
		if (t->next || t->next->data > a)
		{
			p = (Nd*)malloc(sizeof(Nd));
			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;
	} 


}

中间插入结点的核心代码就是

大体就是从头开始查找目标位置,找到之后用一个中间量连接起来就可以

scanf("%d", &a);
	t = head;
	while (t != NULL)
	{
		if (t->next || t->next->data > a)
		{
			p = (Nd*)malloc(sizeof(Nd));
			p->data = a;
			p->next = t->next;
			t->next = p;
			break;
		}
		t = t->next;
	}

附一个之前写的关于学生成绩统计的代码吧,可以大体看一下。(这个主要是了解如何动态申请空间)

宏定义
#define TableHead "学号\t 姓名\t 性别\t 出生日期\t 语文\t 数学\t 英语\t 平均\n"
#define BirthdayOutput stu->bthd.year, stu->bthd.month, stu->bthd.day                   
#define BirthdayInput &stu->bthd.year, &stu->bthd.month, &stu->bthd.day
typedef struct date
{
    int year;
    int month;
    int day;
} DATA;

typedef struct student
{
    int stuID;
    char stuName[20];
    char gender;
    DATA bthd;
    int Chin;
    int Math;
    int Engl;
    float average;
    struct student* next;                 //节点数据类型

} STUDENT;

STUDENT inputStu(STUDENT* stu)
{


    printf("学号(2023001): ");
    scanf("%d", &stu->stuID);

    printf("姓名: ");
    scanf("%s", stu->stuName);
    getchar();

    printf("性别(M,F): ");
    scanf("%c", &stu->gender);

    printf("出生日期(yy-mm-dd): ");
    scanf("%d-%d-%d", BirthdayInput);

    printf("语文(0~100): ");
    scanf("%d", &stu->Chin);

    printf("数学(0~100): ");
    scanf("%d", &stu->Math);

    printf("英语(0~100): ");
    scanf("%d", &stu->Engl);

    stu->average = (float)(stu->Chin + stu->Math + stu->Engl) / 3;

    return *stu;
}

void outputStuTable(STUDENT* stu)
{
    printf("%07d\t", stu->stuID);
    printf("%s\t", stu->stuName);
    printf("%c\t", stu->gender);
    printf("%4d-%02d-%02d\t", BirthdayOutput);
    printf("%d\t", stu->Chin);
    printf("%d\t", stu->Math);
    printf("%d\t", stu->Engl);
    printf("%.2f\n", stu->average);
}

void sortByAverage(STUDENT* stu[], int n)
{
    int i, j;
    STUDENT* temp;
    for (i = 0; i < n; i++)
        for (j = 0; j < n - i - 1; j++)
            if (stu[j]->average < stu[j + 1]->average)
            {
                temp = stu[j];
                stu[j] = stu[j + 1];
                stu[j + 1] = temp;
            }
}

int main()
{
    STUDENT* stu[10];
    STUDENT* p = NULL;
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
    {
        p = (STUDENT*)malloc(sizeof(STUDENT));

        if (p == NULL)
        {
            printf("error");
        }
        inputStu(p);
        stu[i] = p;
    }

    sortByAverage(stu, n);

    printf(TableHead);
    for (int i = 0; i < n; i++)
    {
        outputStuTable(stu[i]);
    }

    for (int i = 0; i < n; i++)
    {
        free(stu[i]);
    }

    return 0;
}

练习题

P7505 「Wdsr-2.5」小小的埴轮兵团

# 「Wdsr-2.5」小小的埴轮兵团

## 题目背景

杖刀偶磨弓是埴轮兵团的首长。

作为埴轮兵长,训练埴轮兵团是很平常的事情。

## 题目描述

磨弓下达命令让埴轮们站成一行。不妨认为它们站在了一个数轴上,每个埴轮的位置就是它脚下数轴的数字。磨弓会告诉你,第 $i$ 个埴轮的位置为 $a_i$ 。**不保证** $\bm {a_i}$ **升序**。

数轴的长度是有限制的,具体的范围是 $[-k,k]$ 。也就是说,如果某个埴轮移出了这个范围,它就脱离了这个队列了,并且不会再次回到队列当中。

为了训练埴轮,磨弓给埴轮们下达了 $m$ 个指令,有以下 3 种:

- 指令 1:**全体埴轮**向数轴的正方向移动 $x$ 个单位长度。
- 指令 2:**全体埴轮**往数轴的反方向移动 $x$ 个单位长度。
- 指令 3:依次报数,统计目前队列里一共有多少个埴轮。

但是磨弓发现,埴轮兵团的大小实在是太大了,以至于执行这些操作变得非常缓慢。尽管如此,磨弓仍然希望你告诉她所有指令 3 的结果。

## 输入格式

第一行共有 $3$ 个整数 $n, m, k$,含义如题面所示。

第二行共有 $n$ 个整数 $a_1, a_2, \cdots, a_n$,表示每个埴轮的位置。

接下来 $m$ 行,有 $1$ 或者 $2$ 个正整数,描述一条指令。首先是一个整数 $\operatorname{op}$,表示这条指令的类型。如果 $1 \leq \operatorname{op} \leq 2$,接下来还会输入一个整数 $x$。

## 输出格式

对于每条指令 3 ,输出一个整数,表示目前还在队列中的埴轮的数目。

## 样例 #1

### 样例输入 #1

```
3 4 3
-1 1 2
2 3
3
1 5
3
```

### 样例输出 #1

```
2
1
```

## 提示

#### 样例 1 说明

一共有三个埴轮。初始时,它们的站位分别是 $[-1,1,2]$ 。

- 第一次操作后,所有埴轮向左移动 $3$ 格,位置变成了  $[\underline{\bm{-4}},-2,-1]$ 。第一个埴轮被移出了数轴。
- 第二次操作后,输出当前的埴轮数目,为 $2$ 个。
- 第三次操作后,所有埴轮向右移动 $5$ 格,位置变成了 $[3,\underline \bm4]$ ,第二个埴轮被移出了数轴。
- 第四次操作后,输出当前的埴轮数目,为 $1$ 个。

#### 样例 2, 3

见下发附件。

#### 数据规模与约定

- 对于 $30\%$ 的数据,$1 \leq n, m \leq 5\times 10^3$;
- 对于另外 $20\%$ 的数据,$1\le k\le 500$;
- 对于 $100\%$ 的数据,$1 \leq n, m \leq 3\times 10^5$,$1 \leq k, x \leq 2 \times 10^9$,$-k \le a_i \le k$ 。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e5+10;
int n,m,l=1,r,op;
ll k,a[N],x,p;
int main()
{
    cin>>n>>m>>k;
    r=n;
    for(int i=1;i<=n;i++)
		cin>>a[i];
	sort(a+1,a+n+1);//排序 
	for(int i=1;i<=m;i++)
	{
		cin>>op;
		if(op==3)//操作3 
		{
			cout<<r-l+1<<endl;
			continue;
		}
		cin>>x;
		if(op==1)//操作1 
		{
			p+=x;
			while(a[r]+p>k&&l<=r)//队尾出队 
				r--;
		}
		else//操作2 
		{
			p-=x;
			while(a[l]+p<-k&&l<=r)//队头出队  
				l++;
		}
	}
	return 0;
}

P1981 [NOIP2013 普及组] 表达式求值

# [NOIP2013 普及组] 表达式求值

## 题目背景

NOIP2013 普及组 T2

## 题目描述

给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。

## 输入格式

一行,为需要你计算的表达式,表达式中只包含数字、加法运算符 `+` 和乘法运算符 `*`,且没有括号,所有参与运算的数字均为 $0$ 到   $2^{31}-1$ 之间的整数。  

输入数据保证这一行只有 `0123456789+*` 这 $12$ 种字符。

## 输出格式

一个整数,表示这个表达式的值。  

注意:当答案长度多于 $4$ 位时,请只输出最后 $ 4$ 位,前导 $ 0$ 不输出。

## 样例 #1

### 样例输入 #1

```
1+1*3+4
```

### 样例输出 #1

```
8
```

## 样例 #2

### 样例输入 #2

```
1+1234567890*1
```

### 样例输出 #2

```
7891
```

## 样例 #3

### 样例输入 #3

```
1+1000000003*1
```

### 样例输出 #3

```
4
```

## 提示

对于 $30\%$ 的数据,$0≤$ 表达式中加法运算符和乘法运算符的总数 $≤100$。

对于 $80\%$ 的数据,$0≤$ 表达式中加法运算符和乘法运算符的总数 $≤1000$。

对于 $100\%$ 的数据,$0≤$ 表达式中加法运算符和乘法运算符的总数 $≤100000$。

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include<stdbool.h>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cstring>
#include<bits/stdc++.h>


int m = 10000;
int t = 0, x = 0, sum = 0;
char c;
int main()
{
    scanf("%d", &t);    //先读取一个数字
    while (scanf("%c",&c) && c!='\n')
    {
        scanf("%d", &x);
        if (c == '*')
            t = t * x % m;
        else
        {
            sum = (sum + t) % m;
            t = x;
        }
            
    }
    printf("%d\n", (sum + t) % m);
    return 0;
}

P1219 [USACO1.5] 八皇后 Checker Challenge

# [USACO1.5] 八皇后 Checker Challenge

## 题目描述

一个如下的 $6 \times 6$ 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

![](https://cdn.luogu.com.cn/upload/image_hosting/3h71x0yf.png)

上面的布局可以用序列 $2\ 4\ 6\ 1\ 3\ 5$ 来描述,第 $i$ 个数字表示在第 $i$ 行的相应位置有一个棋子,如下:

行号 $1\ 2\ 3\ 4\ 5\ 6$

列号 $2\ 4\ 6\ 1\ 3\ 5$

这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。  
并把它们以上面的序列方法输出,解按字典顺序排列。  
请输出前 $3$ 个解。最后一行是解的总个数。

## 输入格式

一行一个正整数 $n$,表示棋盘是 $n \times n$ 大小的。

## 输出格式

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

## 样例 #1

### 样例输入 #1

```
6
```

### 样例输出 #1

```
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
```

## 提示

【数据范围】  
对于 $100\%$ 的数据,$6 \le n \le 13$。

题目翻译来自NOCOW。

USACO Training Section 1.5

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include<stdbool.h>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cstring>
#include<bits/stdc++.h>


using namespace std;
int a[100] = { 0 }, b[100] = { 0 }, c[100] = { 0 }, d[100] = { 0 };   //c 左下到右上    d  左上到右下
int total = 0, n = 0;
void print()
{
    if (total <= 2)
    {
        for (int i = 1; i <= n; i++)
        {
            cout << a[i] << " ";
        }
        cout << endl;
    }
    total++;
}
void queen(int i)
{
    if (i > n) {
        print();
        return;
    }
    else
    {
        for (int j = 1; j <= n; j++)
        {
            if ((!b[j]) && (!c[i + j]) && (!d[i - j + n]))
            {
                a[i] = j;
                b[j] = 1;
                c[i + j] = 1;
                d[i - j + n] = 1;
                queen(i + 1);
                b[j] = 0;
                c[i + j] = 0;
                d[i - j + n] = 0;
            }
        }
    }
}
int main()
{
    cin >> n;
    queen(1);
    cout << total <<endl;
    return 0;
}

  • 23
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值