如何在Linux上搭建Minecraft服务器

如果想和小伙伴们一起联机玩MC,那么完全可以购买一个云服务器后自己创建一个属于自己的世界。并且实测人数少的情况下也不需要有多好的服务器,我就是用搬瓦工19.9刀一年的服务器搭建的。3、4个人玩还是很开心的。下面就是步骤,感觉小白也能尝试着手动搭建一下。

系统要求

下面是度娘的MC系统要求:
1.CPU:双核
2.内存:20-40人2GB,30-60人3GB,60+人8GB
上面就是服务器端的需求,所以如果只是和小伙伴们一起玩,也并不需要多优秀的服务器。下面是我的配置:
1.CPU:单核
2.内存:512MB
3.Linux系统:CentOS 6.5 x86_64

安装Java

MC是用Java写的就不再赘述了,由于服务器端的MC是一个jar包,我们在配置之后通过运行jar包来开启服务器端,同时我们在 PC
上打开后通过IP地址即可搜索并进入服务器。所以我们首先要先安装Java。一般来说默认安装的是有Java 8的,如果没有可以按 照
下面的方法来安装:

1.验证是否安装Java,如果安装就查看版本

java -version
下面是博主的Java版本:

[root@host ~]# java -version
openjdk version “1.8.0_151”
OpenJDK Runtime Environment (build 1.8.0_151-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)
如果不是Java 8或者没有安装,就用下面的方法安装:

sudo yum install java-1.8.0-openjdk

下载MC服务器端

这里有一个要求,就是你和你的小伙伴要拥有同样版本的MC。不同的版本对应着不同的服务器端,所以我们要下载正确的版本。如何看MC版本呢,一般来说MC游戏左上角就写的有了,例如:Mineeraft 1.12。如果没有的同学可以启动MC游戏进入到开始界面即可,下面是博主的MC:

%title插图%num

可以看到左上角跟左下角都有版本号,博主的MC是1.12。

既然知道了版本号,那么用命令就直接下载对应版本的服务器端就可以了。需要根据版本号补全命令格式:

sudo wget https://s3.amazonaws.com/Minecraft.Download/versions/版本号/minecraft_server.版本号.jar
以博主版本为例:

sudo wget https://s3.amazonaws.com/Minecraft.Download/versions/1.12/minecraft_server.1.12.jar
这个命令表示我下载(使用wget命令)了对应版本的jar包。
此时,minecraft_server.1.12.jar就躺在当前目录了。

MC,启动!

上面的jar包下载完成之后,我们稍作准备就可以开启了!这里还是提醒一下对Java不熟悉的同学。我们知道可执行文件是.exe。双击直接运行,那么Java可以生成jar包,就是.jar文件,在Windows上也是可以双击运行的。而我们下载的这个MC服务器端其实就是已经做好的jar包,所以我们在“双击”启动之前还是需要一些配置,以及用Linux的方法来启动。

首先,来看一下内存的使用,输入命令:

free -h
我们可以看到当前内存的使用情况,下面是我输入该命令后的显示:

total used free shared buffers cached
Mem: 506M 172M 333M 152K 51M 53M
-/+ buffers/cache: 67M 438M
Swap: 131M 0B 131M
根据free栏的内存数,我们可以确定该给MC服务器分配多大的内存(当然越多越好啦)。
之后,我们就可以使用命令来运行MC服务器了:

sudo java -Xms[初始启动分配内存] -Xmx[*大分配内存] -jar [jar包所在路径]/minecraft_server.[版本号].jar nogui
还是以博主的为例:

sudo java -Xms120m -Xmx160m -jar /root/mc/minecraft_server.1.12.jar nogui
关于路径是要*对路径的,如果不懂可以在当前目录下使用命令:

pwd
然后就能得到当前目录的*对路径了。

关于命令*后一个参数 nogui,是分开的单词 no gui,意思是不需要图形界面,直接用酷(zhuang)炫(b)的黑框显示,其实这样会大大减小内存的使用,如果你的Linux是有图形界面的,就可以不打这个 nogui。

启动成功

上面的命令输入完成,理论上我们就能启动了!这里注意,我们现在如果在Windows下,等于说已经进入到这个程序中了,所以不能再使用Linux命令,等待参数由0%一直到100%就启动完成啦!下面给出博主启动完成的后几行显示:

[05:58:08] [Server thread/INFO]: Loaded 488 advancements
[05:58:08] [Server thread/INFO]: Preparing start region for level 0
[05:58:09] [Server thread/INFO]: Preparing spawn area: 0%
[05:58:10] [Server thread/INFO]: Preparing spawn area: 41%
[05:58:11] [Server thread/INFO]: Preparing spawn area: 76%
[05:58:11] [Server thread/INFO]: Done (4.263s)! For help, type “help” or “?”
这样就启动成功了,不要有顾虑,直接启动PC端连接服务器进入MC吧!(启动失败的情况下面有一个解决方法)

MC,关闭!

启动之后当前这个窗口就可以不用管啦。博主使用的Xshell,直接*小化。联机完毕之后其实直接关了Xshell就行,自动就断开了,当然也可以输入Ctrl+C,直接终止进程。

MC*常见启动失败-同意协议

我们在*次运行完jar包后,无论是否运行成功,都能发现当前目录下多出了一堆文件,运行失败的时候其实就是配置除了一点问题。我们在当前目录找一下文件:eula.txt。我们需要对这个文件进行一下小编辑:

vi eula.txt
按“i”键进入编辑模式,找到这一行:

eula=false
将false改成true即可。
退出vi编辑器:
1.按 esc
2.输入 :wq
这样就同意了那个“ *终用户许可协议”,反正你要玩就得同意。

MC连接失败

这里是上面都启动成功之后,PC端也搜索到了服务器,但是就是连接失败,这样我们可以修改配置,先在jar包目录下找到文件server.propertices 并编辑:

vi server.propertices
找到这一行:

online-mode:true
将true改为false,这个好像是跟正版有关吧。。。

配置
关于MC服务器端的配置,我们就需要修改这个文件了,同样在jar包所在目录下:

vi server.propertices
可以看到,里面是对当前你创建的这个游戏的各种配置,像选择模式啦、世界生成的种子啦、是否有村民啦等等,就像PC创建世界时的各种选项一样。这里就不再介绍了,需要修改的同学自行百度。

MC,Shell脚本启动!

我们如果一直使用上面那一句启动的话是不是非常麻烦!每次都要复制粘贴,那么我们可以写一个简单的Shell脚本,放在jar包所在目录,每次启动的时候直接启动脚本就能进入游戏了,完全不需要Shell编程基础,直接复制粘贴即可!(玩游戏就不要想太多!当然玩爽之后可以了解一下Shell编程)

vi start.sh
进入编辑模式后输入代码:

#!/bin/sh

java -Xms120m -Xmx160m -jar /root/mc/minecraft_server.1.12.jar nogui;
是不是非常简单呢!其实就是让脚本帮你搓启动命令,而你仅需要运行一下脚本即可:

bash start.sh
MC,启动!

关于PC连接问题

之所以放到*后是怕有同学上面的都完成之后发现不知道如何连接到服务器上,或者说根本不知道服务器的IP地址。这里就说一下Linux下如何查看IP地址:

ifconfig
就是如此简单粗暴,一般来说,我们看eth0网卡就行了。如果嫌麻烦,直接看类似格式:192.168.0.1差不多的就是IP地址啦,其实写着 inet addr 的,后面的就是IP地址。然后在PC端多人游戏中搜索服务器时将IP地址输入就可以了。

 

奇偶链表(JS实现)

奇偶链表(JS实现)

1 题目
给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
示例 1:
输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL
示例 2:
输入: 2->1->3->5->6->4->7->NULL
输出: 2->3->6->7->1->5->4->NULL
说明:
应当保持奇数节点和偶数节点的相对顺序。
链表的*个节点视为奇数节点,第二个节点视为偶数节点,以此类推。

链接:https://leetcode-cn.com/problems/odd-even-linked-list

2 思路
这道题我的思路*遍遍历,我给每个节点添加一个_next指针,奇数节点指向下一个奇数节点,而偶数节点指向下一个偶数节点,第二次遍历将_next替换为原来的next指针

3代码
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var oddEvenList = function(head) {
if (!head || !head.next) return head;
let link = head;

let headOdd = head;
let headEven = secondNode = head.next;
let lastOddNode;
while(headOdd || headEven) {
if (headOdd) {
headOdd._next = (headOdd.next && headOdd.next.next) || null;
if (!headOdd._next) {
lastOddNode = headOdd;
}
headOdd = headOdd._next;
}

if (headEven) {
headEven._next = (headEven.next && headEven.next.next) || null;
headEven = headEven._next;
}
}

while(head) {
let nextNode = head.next;
head.next = head._next;
delete head._next;
head = nextNode;
}

lastOddNode.next = secondNode;

return link;
};

零钱兑换(JS实现)

零钱兑换(JS实现)

1 题目
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的*少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1

链接:https://leetcode-cn.com/problems/coin-change

2 思路
这道题考察贪心+回溯算法,我们先把硬币排序,然后构造一棵树,先从大面值的硬币开始,逐级相减,直到总金额为0,即找到了目标的*优组合,题解中还可以用动态规划的方法来做

3代码
/**
* @param {number[]} coins
* @param {number} amount
* @return {number}
*/
var coinChange = function(coins, amount) {
coins.sort((a,b) => a-b);

if (amount === 0) return 0;
if (amount < coins[0]) return -1;

let ans = 999999;
d(amount, coins.length – 1, 0, coins);

function d(num, index, len, coins) {
if (num === 0) {
ans = Math.min(ans, len);
return;
};
if (index < 0) return;

for (let k=Math.floor(num / coins[index]); k >=0 && k + len < ans; k–) {
d(num – coins[index] * k, index – 1, len + k, coins);
}
}

return ans === 999999 ? -1 : ans;
};

摆动排序 II(JS实现)

摆动排序 II(JS实现)

1 题目
给定一个无序的数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]… 的顺序。
示例 1:
输入: nums = [1, 5, 1, 1, 6, 4]
输出: 一个可能的答案是 [1, 4, 1, 5, 1, 6]
示例 2:
输入: nums = [1, 3, 2, 2, 3, 1]
输出: 一个可能的答案是 [2, 3, 1, 3, 1, 2]
说明:
你可以假设所有输入都会得到有效的结果。
进阶:
你能用 O(n) 时间复杂度和 / 或原地 O(1) 额外空间来实现吗?

链接:https://leetcode-cn.com/problems/wiggle-sort-ii

2 思路
很明显,我做这道题就是先把数组排序,然后将数组分为两部分,依次构造新数组的,题解中有O(n)的算法,其先用快速选择法,找到数组的中位数,然后将小于等于中位数的数放置在左侧,大于中位数的放置在右侧,这样就成了两部分了

3代码
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var wiggleSort = function(nums) {
nums.sort((a,b) => a-b);

let mid = nums.length % 2 === 0 ? Math.floor(nums.length / 2) : Math.floor(nums.length / 2) + 1;

const res = [];

let low = mid – 1;
let high = nums.length – 1;
while (low >= 0 && high >= mid) {
res.push(nums[low–]);
res.push(nums[high–]);
}

if (low >= 0) res.push(nums[low–]); //从后向前进行插入
if (high >= mid) res.push(nums[high–]); //从后向前进行插入

for (let i=0; i<res.length;i++) {
nums[i] = res[i];
}
};

CentOS搭建mc服务器

安装配置
1. 安装配置java环境,用Java1.8
2. 获取mc服务器jar包:
wget https://s3.amazonaws.com/Minecraft.Download/versions/[version]/minecraft_server.[version].jar

# 如采用1.11.2版本服务器端
wget htts://s3.amazonaws.com/Minecraft.Download/versions/1.11.2/minecraft_server.1.11.2.jar

3. 启动mc服务器端:
java -Xms**m -Xmx**m -jar [path]/minecraft_server.[version].jar nogui

# 1.11.2版本
java -Xms512m -Xmx768m -jar /root/mc/minecraft_server.1.11.2.jar nogui
# -Xms:初始启动分配的内存(-Xms512m)
# -Xmx:*大分配的内存(-Xmx768m)
# nogui:用于以基于文本的界面来显示,可减少内存使用。如果使用图形化界面,那么移除nogui选项。

4. 同意*终用户许可协议 EULA
首次启动不会成功启动,会生成一个eula.txt 文件。用vim打开,将行 eula = false 更改为 eula = true,并保存文件,表示同意许可协议。

5. 服务器要开25565端口
服务器端默认使用25565端口,可配置,配置详情参考下一条。

如腾讯云服务器设置步骤:

控制台-云服务器-安全组-安全组规则-添加规则:
来源:0.0.0.0/0
协议端口:TCP:25565

6. 修改server.propertices
如果客户端连接报错,修改服务器端server.propertices文件:
把 online_mode=true 改成online_mode=false,重启服务再试。
这个选项表示是否连接正版服务器验证用户。

其中server.propertices是mc服务端配置文件,可设置游戏难度、世界类型、游戏模式、允许玩家数量、世界大小、黑白名单等等。
配置文件内容:

#Minecraft server properties
#Fri Jan 05 22:45:30 CST 2018
generator-settings=
op-permission-level=4
allow-nether=true
level-name=world #存档名称,也就是读取的存档文件夹的名称,默认为world
enable-query=false
allow-flight=false
announce-player-achievements=true
server-port=25565 #端口,客户端连接的话要指定这个端口,服务器防火墙要开放这个端口。可以不指定,默认为:25565
level-type=DEFAULT
enable-rcon=false
force-gamemode=false
level-seed= #地图种子
server-ip=
max-build-height=256
spawn-npcs=true
white-list=false
spawn-animals=true
snooper-enabled=true
hardcore=false
online-mode=false #是否连接正版服务器校验
resource-pack=
pvp=true
difficulty=1
enable-command-block=false
player-idle-timeout=0
gamemode=0
max-players=20 #*大玩家数
spawn-monsters=true
view-distance=10
generate-structures=true
motd=A Minecraft Server

另外服务器启动后可以在后台执行命令。如设置超级管理员op命令:

op player1 # 把player1设为op,然后player1就能输入作弊码了。
1
安装mod
若要在服务器上安装mod,需下载相应版本的forge jar包(假设1.7.10版本,则为forge-1.7.10-10.13.4.1558-1.7.10-universal.jar),将forge-1.7.10-10.13.4.1558-1.7.10-universal.jar同客户端.minecraft文件夹下libraries目录一起拷贝到服务器端(同服务器jar位于同一目录)。然后执行:

java -Xms512m -Xmx768m -jar /root/mc/forge-1.7.10-10.13.4.1558-1.7.10-universal.jar nogui

执行成功后就会生成mods目录,然后将相关mod的jar包放到mods目录里,重启服务器就可以了(启动服务器也使用上面forge jar包的命令)。

注意客户端需要安装了同样的mod,mod才能有效。

另外:mc1.12用forge-1.12-14.21.1.2443-installer.jar安装mod,用forge-1.7.10-10.13.4.1558-1.7.10-universal.jar启动。

虚拟终端screen
另外为了让此服务器程序一直运行,可以安装虚拟终端screen:

yum install -y screen

开终端mc,然后在里面执行命令:

screen -S mc # 开一个名为mc的session
… # 然后是要在虚拟终端mc下执行的命令
# 将终端后台:按`ctrl+a`,然后按`d`。

回到终端mc:

screen -r mc

列出已经打开的session:

screen -ls #或
screen -list

判断题(15) python篇

判断题(15) python篇

1061. 判断题(15)
时间限制
400 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
CHEN, Yue
判断题的评判很简单,本题就要求你写个简单的程序帮助老师判题并统计学生们判断题的得分。

输入格式:

输入在*行给出两个不超过100的正整数N和M,分别是学生人数和判断题数量。第二行给出M个不超过5的正整数,是每道题的满分值。第三行给出每道题对应的正确答案,0代表“非”,1代表“是”。随后N行,每行给出一个学生的解答。数字间均以空格分隔。

输出格式:

按照输入的顺序输出每个学生的得分,每个分数占一行。

输入样例:
3 6
2 1 3 3 4 5
0 0 1 0 1 1
0 1 1 0 0 1
1 0 1 0 1 0
1 1 0 0 1 1
输出样例:
13
11
12
l1=input().split()
l2=input().split()
l3=input().split()
b=0
c=[]
for i in range(int(l1[0])):
a=input().split()
for x,y in enumerate(a):
if y==l3[x]:
b = b + int(l2[x])
c.append(b)
for i in c:
print(i)

 

MC原版服务器搭建教程

前言

  • 本教程适用于有自己的服务器并希望和好友进行原版MC游戏的人使用(正版盗版通用)
  • 本教程完成后将建立一个完全纯净无法添加任何mod的服务器,请酌情阅读

准备

  1. 一枚可以正常访问的服务器
    • 本教程使用腾讯云主机进行演示
  2. 官方提供的服务器jar
    • 别忘了安装java哦
      在cmd中输入java -version来确认安装是否成功
    • 注意!请在服务器上下载该JAR
      推荐访问MCBBS进行下载 论坛中会实时更新*新的游戏包,而本教程将使用MineCraft1.12进行演示
    • 论坛地址:MCBBS
      img_a6b81efe21cbbd8c321595fa26fe00ad.png
      MCBBS
    • MineCraft1.12服务器jar下载地址:MC1.12服务器JAR
      img_df7a3f8cfd98b4efc004118c341b51bd.png
      获取JAR
  1. mc原版客户端
  • 注意!客户端必须和服务器JAR版本相同
    推荐使用启动器进行下载,本教程将使用HMCL启动器
  • HMCL启动器下载链接:HMCL

服务器搭建

好了,现在需要的基本都已经准备好了,接下来就是非常简单的搭建过程啦
注意!在此步骤之前请确保游戏所需端口开放,若不确定请自行配置,或移步服务器端口开放教程进行参考

  • MC默认端口号:25565

启动服务器

还记得刚开始下载的服务器JAR么?没错,它就是一个完整的服务器。现在我们只需要启动它就可以了
把JAR包放到一个合适的地方,然后在相同文件夹下新建一个文本文档,命名为start.cmd,右键编辑后粘贴以下内容:

  1. @echo off
  2. java -Xms1g -Xmx1g -jar 你的服务器包名.jar
  3. pause
新建脚本

 

现在双击start.cmd启动服务器

 

启动服务器

好了?服务器启动了?当然没有,在服务器启动前我们需要先同意EULA协议。对就是文件夹里那个eula.txt。现在按回车关闭cmd,然后打开eula.txt,将其中的eula = false 修改成true。

 

确认eula协议

然后再次双击start.cmd

 

启动成功

当cmd显示Done!时即说明服务器启动成功,在cmd中输入stop保存并关闭服务器

服务器配置

现在服务器已经启动好了,接下来我们要进行非常简单的配置,真的非常简单,别看下面一大堆,其实只有*条时必须要做的,其他都是可选项。
注意!在进行接下来的操作时请保证服务器已经关闭
在服务器根文件夹中有个叫server.properties的文件,我们接下来的操作都会在这个文件中完成。此文件编辑不支持中文,true代表执行,false代表不执行 推荐使用notepad进行设置

设置文件
  • 打开文件后搜索online-mode并将其值改为false,否则盗版游戏将无法连接(必须)
  • server-port 为服务器的游戏端口,修改为你想开启的端口,若为默认则进入游戏时无需输入端口号。注意!请确保此端口和服务器安全组策略中开放的端口一致
  • level-name 的值为地图文件夹名,将你想玩的地图放在根文件夹中并修改此值即可。(或者替换world文件夹内容)
  • pvp 是否开启玩家伤害
  • allow-flight 是否允许飞行
  • rcon.password 远程访问服务器的密码,可以留空或删除
  • spawn-npcs 是否生成NPC
  • spawn-animals 是否生成动物
  • spawn-monsters 是否生成怪物
  • hardcore 是否开启*限模式
  • difficulty 游戏难度
  • gamemode 玩家*次进入游戏时的游戏模式
  • max-players 同时在线的*大玩家数
  • motd 服务器欢迎信息

更多设置请参考服务器详细设置

至此,服务器设置全部完成。

客户端操作

  1. 打开HMCL下载与服务端相同版本的游戏,下载过程非常简单不再赘述
  2. 进入游戏选择多人游戏
  3. 选择直接连接或者添加服务器
  4. 输入 ip地址 : 端口号(若为默认端口的话就不必填端口号)点击完成加入服务器!
    注意!请确保其中冒号“:”为英文字符,

OK!至此教程结束,和你的小伙伴愉快的玩耍吧!

反转链表

1025. 反转链表 (25)
时间限制
300 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
CHEN, Yue
给定一个常数K以及一个单链表L,请编写程序将L中每K个结点反转。例如:给定L为1→2→3→4→5→6,K为3,则输出应该为3→2→1→6→5→4;如果K为4,则输出应该为4→3→2→1→5→6,即*后不到K个元素不反转。

输入格式:

每个输入包含1个测试用例。每个测试用例第1行给出第1个结点的地址、结点总个数正整数N(<= 105)、以及正整数K(<=N),即要求反转的子链结点的个数。结点的地址是5位非负整数,NULL地址用-1表示。

接下来有N行,每行格式为:

Address Data Next

其中Address是结点地址,Data是该结点保存的整数数据,Next是下一结点的地址。

输出格式:

对每个测试用例,顺序输出反转后的链表,其上每个结点占一行,格式与输入相同。

输入样例:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
输出样例:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1
# -*- coding: utf-8 -*-
# 思路:从给定的链首到链末共有数据个数n加1项,id为前n项,next为后n项
def link(address,head,li): # 采用递归将链表所用节点依次存入列表
if head in address:
arrow = address[head]
li.append(arrow)
return link(address,arrow,li)
else:
return li
head,N_all,cell = input().split() # 读取*行输入:首项元素id,元素个数N_all,反转间隔cell
N_all,cell = int(N_all),int(cell) # 将N与cell转换为整数
address,data = {},{} # 初始化两个字典,其中address保存id-next关系,data保存id-data关系
for i in range(N_all): # 将输入信息存入address和data中
a,b,c = input().split()
address[a],data[a] = c,b
# 调用link()函数将所给信息按链接顺序存入id_plus,有N_all+1个元素,末项为链尾指针,指向未知id或为-1
id_plus = link(address,head,[head]) # 第三项必须为[head]而不是[],因为link()函数无法添加*个id
id_plus[-1] = ‘-1’ # 指定链尾指针指向-1
N_e = len(id_plus) – 1 # id_plus中的元素个数为可链接到的元素,从首项到*后的-1,实际对应的数据个数应减1
num, rem = N_e // cell, N_e % cell # 判断要对那些数据进行反转
if num: # 可链接到的数据个数不小于反转间隔
for i in range(num):
id_plus[(i*cell):((i+1)*cell)] = id_plus[(i*cell):((i+1)*cell)][::-1] # 反转
for k,v in enumerate(id_plus[:-1]): # 按规定格式,打印id,data,next
s = ‘{} {} {}’.format(v,data[v],id_plus[k+1])
print(s)
有一个测试点超时,请大神指教!
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100010 //用双向静态链表来解决本问题,定义链表长度为100010
typedef struct Node //定义结点
{
int data; //存储数据
int addr; //存储当前地址
int next; //后指针,存储下一节点的地址
int prior; //前指针,存储前一节点的地址
}Node;
int num,n,address,sum=1; //num为输入节点的总数,n为每次反转节点的个数,address为*个结点的地址,sum为计数器,记录有效节点的个数
void read(Node Nodes[]); //读取数据,建立链表
void reverse(Node Nodes[]); //反转链表,输出结果
int main()
{
Node Nodes[MAXSIZE];
scanf(“%d%d%d”,&address,&num,&n);
read(Nodes);
reverse(Nodes);
return 0;
}

void read(Node Nodes[]) //读取数据
{
int i,addre,addre_p; //addre为当前结点的地址,addre_p为前一节点的地址
for (i=0;i<num;i++) //将每个结点放在地址对应下标的数组单元中,并使当前结点的后指针指向下一节点
{
scanf(“%d”,&addre);
scanf(“%d%d”,&Nodes[addre].data,&Nodes[addre].next);
Nodes[addre].addr=addre;
}
addre=address;
Nodes[addre].prior=-1; //使*个结点的前指针指向-1
addre_p=Nodes[addre].addr; //记录*个结点的地址
addre=Nodes[addre].next; //使下一个结点成为当前结点
while (addre!=-1)
{
Nodes[addre].prior=addre_p; //使当前结点的前指针指向前一个结点
addre_p=Nodes[addre].addr; //使当前结点成为前结点
addre=Nodes[addre].next; //使下一个结点成为当前结点
sum++; //有效结点数+1
}
}

void reverse(Node Nodes[]) //反转链表,输出数据
{
int i,addre,j,addre_save,addre_prior; //addre为当前结点的地址,addre_save为每次反转前的n个结点中*后一个结点的地址,
addre=address; //addre_prior为每次反转前的n个结点中首个结点的地址
if (n==1||n>sum) //如果每次反转结点的个数等于1或大于有效结点的个数,则不反转,依次输出即可
{
while(addre!=-1)
{
if (Nodes[addre].next==-1)
printf(“%05d %d %d\n”,Nodes[addre].addr,Nodes[addre].data,Nodes[addre].next);
else
printf(“%05d %d %05d\n”,Nodes[addre].addr,Nodes[addre].data,Nodes[addre].next);
addre=Nodes[addre].next;
}
}else //否则,进行反转,每次反转n个结点
{
for (i=0;i<sum/n;i++) //总反转的次数为 sum/n
{
for (j=0;j<n-1;j++) //寻找每次反转前的n个结点中*后一个结点的地址
{
addre=Nodes[addre].next;
}
addre_save=addre; //保存本次反转前*后一个结点的地址
if (i!=0) //*次反转不输出,输出前一次反转后的n个结点中*后一个结点的地址,数据以及本次反转后*个结点的地址(注意,这样每次反转才能衔接)
printf(“%05d %d %05d\n”,Nodes[addre_prior].addr,Nodes[addre_prior].data,Nodes[addre].addr);
for (j=0;j<n-1;j++) //除*后一个结点,依次输出本次反转后的其余结点
{
printf(“%05d %d %05d\n”,Nodes[addre].addr,Nodes[addre].data,Nodes[addre].prior);
addre=Nodes[addre].prior;
}
addre_prior=addre; //保存本次反转*后一个结点的地址
if (Nodes[addre_save].next==-1) //如果有效结点已用完,即没有剩余有效结点,则输出*后一个结点,注意其下一个结点地址为-1
printf(“%05d %d %d\n”,Nodes[addre].addr,Nodes[addre].data,-1);
else if (i==sum/n-1) //如果这是*后一次反转,则输出*后一个结点,注意其下一个结点的地址为不反转的*个结点的地址
printf(“%05d %d %d\n”,Nodes[addre].addr,Nodes[addre].data,Nodes[addre_save].next);
addre=Nodes[addre_save].next; //使下次反转前的*个结点成为当前结点
}
for (i=0;i<sum%n;i++) //依次输出剩余不需要反转的结点
{
if (Nodes[addre].next==-1)
printf(“%05d %d %d\n”,Nodes[addre].addr,Nodes[addre].data,Nodes[addre].next);
else
printf(“%05d %d %05d\n”,Nodes[addre].addr,Nodes[addre].data,Nodes[addre].next);
addre=Nodes[addre].next;
}
}
}
用双向静态链表解决,这次不再超时

Python爬虫之网页电子书批量爬取

 

小说迷有福了。学会这个,不用再受网页端广告的骚扰,也不用再花钱去各个小说平台看了。自己批量爬取他不香吗?

对于爱学习的朋友来说也是福音呀。各种资料去爬取,保存下来。更加有利于提高自己的学习效率。

上述两点都是小道,*重要的是爬虫学习的好,是可以工作或者去接单挣外快的。

python爬虫学习实践之电子书爬取

1.获取网页信息

import requests #导入requests库
”’
获取网页信息
”’
if __name__ == ‘__main__’: #主函数入口
target = ‘https://www.xsbiquge.com/78_78513/108078.html’#要爬取的目标地址
req = requests.get(url=target) #进行get请求
req.encoding=’utf-8′ #设置编码
print(req.text) #打印输出

2.引入BeautifulSoup对网页内容进行解析

import requests #导入requests库
from bs4 import BeautifulSoup #引入BeautifulSoup库

”’
引入BeautifulSoup对网页内容进行解析
获取网页电子书文本信息
”’
if __name__ == ‘__main__’: #主函数入口
target = ‘https://www.xsbiquge.com/78_78513/108078.html’#要爬取的目标地址
req = requests.get(url=target) #发起请求,获取html信息
req.encoding=’utf-8′ #设置编码
html = req.text #将网页的html信息保存在html变量中
bs = BeautifulSoup(html,’lxml’) #使用lxml对网页信息进行解析
texts = bs.find(‘div’,id=’content’) #获取所有<div id = “content”>的内容
print(texts) #打印输出

3.切分数据,去掉空格,提取文字

import requests #导入requests库
from bs4 import BeautifulSoup #引入BeautifulSoup库

”’
引入BeautifulSoup对网页内容进行解析
获取网页电子书文本信息
*后一句texts.text 是提取所有文字,然后再使用 strip 方法去掉回车,
*后使用 split 方法根据 \\xa0 切分数据,因为每一段的开头,都有四个空格
”’
if __name__ == ‘__main__’: #主函数入口
target = ‘https://www.xsbiquge.com/78_78513/108078.html’#要爬取的目标地址
req = requests.get(url=target) #发起请求,获取html信息
req.encoding=’utf-8′ #设置编码
html = req.text #将网页的html信息保存在html变量中
bs = BeautifulSoup(html,’lxml’) #使用lxml对网页信息进行解析
texts = bs.find(‘div’,id=’content’) #获取所有<div id = “content”>的内容
print(texts.text.strip().split(‘\\xa0’*4)) #打印输出

4.查看章节列表

import requests #导入requests库
from bs4 import BeautifulSoup #引入BeautifulSoup库

”’
查看章节列表信息
引入BeautifulSoup对网页内容进行解析
获取网页电子书文本信息

”’
if __name__ == ‘__main__’: #主函数入口
target = ‘https://www.xsbiquge.com/78_78513/’#要爬取的目标地址,《元尊》的章节目录网址
req = requests.get(url=target) #发起请求,获取html信息
req.encoding=’utf-8′ #设置编码
html = req.text #将网页的html信息保存在html变量中
bs = BeautifulSoup(html,’lxml’) #使用lxml对网页信息进行解析
chapters = bs.find(‘div’,id=’list’) #获取所有<div id = “list”>的内容
chapters = chapters.find_all(‘a’) #找到list中的a标签中的内容
for chapter in chapters:
print(chapter) #打印章节列表

5.获取章节目录和章节链接

import requests #导入requests库
from bs4 import BeautifulSoup #引入BeautifulSoup库

”’
查看章节列表信息
引入BeautifulSoup对网页内容进行解析
获取网页电子书文本信息

”’
if __name__ == ‘__main__’: #主函数入口
server = ‘https://www.xsbiquge.com’
target = ‘https://www.xsbiquge.com/78_78513/’#要爬取的目标地址,《元尊》的章节目录网址
req = requests.get(url=target) #发起请求,获取html信息
req.encoding=’utf-8′ #设置编码
html = req.text #将网页的html信息保存在html变量中
bs = BeautifulSoup(html,’lxml’) #使用lxml对网页信息进行解析
chapters = bs.find(‘div’,id=’list’) #获取所有<div id = “list”>的内容
chapters = chapters.find_all(‘a’) #找到list中的a标签中的内容
for chapter in chapters:
url = chapter.get(‘href’) #获取章节链接中的href
print(“《”+chapter.string+”》”) #打印章节名字
print(server+url) #将电子书网站与获取到的章节连接进行拼接,得到每一个章节的链接

6.整合数据,下载电子书文档

import requests #导入requests库
from bs4 import BeautifulSoup #引入BeautifulSoup库
import time
from tqdm import tqdm

”’
查看章节列表信息
引入BeautifulSoup对网页内容进行解析
获取网页电子书文本信息

”’
def get_content(target):
req = requests.get(url=target) # 发起请求,获取html信息
req.encoding = ‘utf-8’ # 设置编码
html = req.text # 将网页的html信息保存在html变量中
bf = BeautifulSoup(html, ‘lxml’) # 使用lxml对网页信息进行解析
texts = bf.find(‘div’, id=’content’) # 获取所有<div id = “content”>的内容
content = texts.text.strip().split(‘\\xa0’ * 4)
return content

if __name__ == ‘__main__’: #主函数入口
server = ‘https://www.xsbiquge.com’ #电子书网站地址
book_name = ‘《元尊》.txt’
target = ‘https://www.xsbiquge.com/78_78513/’#要爬取的目标地址,《元尊》的章节目录网址
req = requests.get(url=target) #发起请求,获取html信息
req.encoding=’utf-8′ #设置编码
html = req.text #将网页的html信息保存在html变量中
chapter_bs = BeautifulSoup(html,’lxml’) #使用lxml对网页信息进行解析
chapters = chapter_bs.find(‘div’,id=’list’) #获取所有<div id = “list”>的内容
chapters = chapters.find_all(‘a’) #找到list中的a标签中的内容
for chapter in tqdm(chapters):
chapter_name = chapter.string #章节名字
url = server + chapter.get(‘href’) #获取章节链接中的href
content = get_content(url)
with open(book_name,’a’,encoding=’utf-8′) as f:
f.write(“《”+chapter_name+”》”)
f.write(‘\n’)
f.write(‘\n’.join(content))
f.write(‘\n’)

刚开始下载的时候可能会有点慢,下载一本书十分钟。后续碰到更好的方式也会分享出来的了。大家有更好的建议也可以一起交流哈。

Python动态类型

Python动态类型

Python动态类型
在python中,我们使用变量时,并没有声明变量的存在和类型。类型是在运行过程中自动决定的。

a = 3
1
python将会执行三步去完成上面这个请求。

1.创建一个对象代表3

2.创建一个变量a,如果a未创建。

3.将变量a与对象3相连接。

可以将变量a看作对象3的一个引用。

a = 3
b = a
1
2
多个变量可以指向同一个对象,在Python中叫共享引用。

Python在每个对象中保持了一个计数器,用于记录当前指向该对象的引用的数目,一旦计数器被设置为0,该对象的内存空间就会自动回收。

原处修改对象
由于共享引用的存在,有一些对象和操作会在原处修改对象。

Python中对象可分为可变类型对象和不可变类型对象。

可变对象:列表,字典

不可变对象:数字,字符串,元组

如果变量是不可变对象的引用,对变量名的修改不会影响其他变量,而是直接连接到修改的对象。

a = 3
b = a
print(a)# 3
print(b)# 3

a = 4
print(a)# 4
print(b)# 3

如果变量是可变对象的引用,对变量名的修改会影响其他变量。

a = [1,2,3]
b = a
print(a)# [1, 2, 3]
print(b)# [1, 2, 3]

a[0] = 4
print(a)# [4, 2, 3]
print(b)# [4, 2, 3]

拷贝
所以当你需要创建一个与原列表一样同时又独立于原列表的列表时,可以使用拷贝。

下面介绍*常用的两种。

a = [1,2,3]
b = a[:]
print(a)# [1, 2, 3]
print(b)# [1, 2, 3]

a[0] = 4
print(a)# [4, 2, 3]
print(b)# [1, 2, 3]

此时b引用的是a所引用的对象的拷贝。a,b指向不同的内存区域。

在字典和集合中,无法使用这种方法。

可以使用标准库中的copy模块

import copy

a = [1,2,[3]]
b = copy.copy(a)# 浅拷贝
c = copy.deepcopy(a)# 深拷贝

a[0] = 0
a[-1].append(4)

print(a)# [0, 2, [3, 4]]
print(b)# [1, 2, [3, 4]]
print(c)# [1, 2, [3]]

浅拷贝中可变对象中嵌套的可变对象的引用还是原来的引用。