因为这道题,我写了一个类(BigInteger--cpp实现
为什么需要大数加减类?
对于计算机而言,基本的数据类型一般最多为64位数据表示范围,这个范围是有限的,没法无限的表示所有的数据,那么有没有一种方式能够表示所有的大数,并完成加减乘除呢?
答案肯定是有的,由于数据都是由一位一位的数字所组成,我们只需要用数组中的每一位表示一位数字,便可完成对大数的模拟了。
那么我们说明时候需要用到大数模拟呢?对竞赛人而言,有很多题目实际上就是高精度大数模拟类型,而对于普通的程序员而言,大数模拟也仅是在做某个逻辑运算而保证不会溢出的最佳策略,那么大家难道不好奇如何实现一个大数模拟类吗?
现在就从封装一个简单的加减类开始了解这样一个大数模拟是怎么实现的👀
大数加减类实现详解
一、流程图总览
- 如图总体来说分为五部分:
- 静态成员函数:属于类的公共接口(核心)
- 构造和析构函数:构造对象以及析构对象
- 成员数据:用于运算的数据以及表示对象的数据
- 运算符重载:用于自定义运算方式(核心)
- 内部成员函数:属于对象的公共接口
二、成员数据和构造函数详解
- 成员数据
bool f; //是否是负数的标记
char *nums; //存储非符号的大数各个位
int length; //nums的数据长度
int capacity; //nums的可用容量
- 构造和析构
//缺省构造函数
BigInteger() : length(0), capacity(1), f(false) {
nums = new char[capacity];
}
//用于转化普通字符串的构造函数
BigInteger(const char *n) : length(strlen(n)), f(false) {
int start = 0;
if (n[0] == '-') {
f = true;
start++;
}
while (start<length&&n[start] == '0')start++;
capacity = length * 10;
nums = new char[capacity];
std::copy(n + start, n + length, nums);
length = length - start;
}
//拷贝构造函数
BigInteger(BigInteger &a) {
capacity = a.capacity;
length = a.length;
f = a.f;
nums = new char[capacity];
std::copy(a.nums, a.nums + length, nums);
}
//移动构造函数:这里调用了等于号,根据a的类型来决定用哪个等于号
BigInteger(BigInteger &&a) :length(0){
*this = a;
}
//析构函数
~BigInteger() {
delete[] nums;
}
三、(算法核心)静态成员函数和运算符重载详解
static Swap()
//调用std的swap实现对基本数据的交换
static void Swap(BigInteger &a, BigInteger &b) {
std::swap(a.length, b.length);
std::swap(a.capacity, b.capacity);
std::swap(a.f, b.f);
std::swap(a.nums, b.nums);
}
static compare()
//不看符号比较nums的大小:表示a是否比b大
static bool compare(const BigInteger &a,const BigInteger &b) { //比较纯nums大小(不看符号
int n1 = a.length;
int n2 = b.length;
if (n1 != n2)return n1 > n2; //返回a和b哪个大,true则位a大
int i = 0;
while (i < n1 && a.nums[i] == b.nums[i])i++; //a b一样长的情况下,比较两个的值
if (i == n1)
return false;
return a.nums[i] > b.nums[i];
}
static isEqual()
//表示a和b是否相等
bool isEqual(BigInteger &a, BigInteger &b) {
if (a.f != b.f || (a.length != b.length))return false;
int i = 0;
while (i < a.length && a.nums[i] == b.nums[i])i++;
return i == a.length && a.f == b.f;
}
(*核心算法)static add()
不看符号的加法,符号这方面由重载加法运算符控制。
static BigInteger add(BigInteger &a, BigInteger &b) { //不看符号的加法
a.reverse();//尾端对齐
b.reverse();
BigInteger t;
int up = 0;
int len = a.length > b.length ? a.length : b.length;
for (int i = 0; i < len; i++) {
int ta = i < a.length ? a[i] - '0' : 0;
int tb = i < b.length ? b[i] - '0' : 0;
int base = ta + tb + up;
t.push_back(base % 10 + '0');
up = base / 10;
}
if (up)
t.push_back(up + '0');
t.reverse();//返回原位
a.reverse();
b.reverse();
return t;
}
(*核心算法)static minus()
不看符号的减法,默认了a的nums大小(不看符号)是比b大的。
static BigInteger minus(BigInteger &a, BigInteger &b) {
a.reverse();
b.reverse();
BigInteger t;
int len = a.length > b.length ? a.length : b.length;
for (int i = 0; i < len; i++) {
int ta = i < a.length ? a[i] - '0' : 0;
int tb = i < b.length ? b[i] - '0' : 0;
int base = ta - tb;
if (base < 0) {
base += 10;
a[i + 1]--;
}
t.push_back(base + '0');
}
t.reverse();
a.reverse();
b.reverse();
return t;
}
char &operator[]
char &operator[](int i) {
return nums[i];
}
BigInteger &operator=
用了两个版本--右值引用和左值引用版本
- 右值引用延长寿命,用交换的方式实现(毕竟是将亡值
BigInteger &operator=(BigInteger&& a) { //Swap&Copy方式实现右值赋值重载
Swap(*this, a);
return *this;
}
- 左值引用深拷贝
BigInteger &operator=(const BigInteger &a) {//深拷贝
if (length != 0)//如果不是初始化调用的 = ,则肯定需要先把原来的内存delete掉
delete[]nums;
capacity = a.capacity;
length = a.length;
f = a.f;
nums = new char[capacity];
std::copy(a.nums, a.nums + length, nums);
return *this;
}
bool operator<
重载了小于号,好处在于可以直接利用stl进行各种排序操作了。
注意:一定要写成const版本的成员函数,不然STL库无法调用,因为STL库中的所有比较都是基于const对象。
bool operator<(const BigInteger &a) const {
if (f && !a.f) { //其中一个为负数,则那个是更小的
return true;
} else if (!f && a.f)
return false;
if (f) { //两者都为负数的情况,左边的值要更大则为true
return compare(*this, a);
}//两者均为正数,则值更小的在左边为true
return compare(a, *this);
}
(*核心算法)BigInteger operator+
利用静态成员函数完成无符号的加减,然后在这里进行判断各种符号情况,根据不同的符号情况进行不同的加法处理。
- 注意在调用minus之前需要比较两个数的nums谁更大,更大的放在第一个参数上!
BigInteger operator+(BigInteger &a) {
BigInteger res;
bool flag;
if (a.f && f) { //同为负数情况,直接相加,再改符号
res = add(*this, a);
flag = true;
} else if (a.f && !f) {//左正右负
if (compare(a, *this)) { //看负数对应的nums是否比正数大
flag = true;
res = minus(a, *this);
} else {
flag = false;
res = minus(*this, a);
}
} else if (!a.f && f) {
if (compare(*this, a)) { //与上一个相同
flag = true;
res = minus(*this, a);
} else {
flag = false;
res = minus(a, *this);
}
} else { //同时为正数就是最简单的加法
flag = false;
res = add(*this, a);
}
res.f = flag;
return res;
}
(*核心算法)BigInteger operator-
同样是分类讨论,同样是根据不同的类型调用minus和add函数。
- 与正数不同的处理在于对符号的处理,如果同为负数,则需要判断两者是否相等,防止两数相等相减后减为
0
,而被处理为-0
。
BigInteger operator-(BigInteger &a) {
BigInteger res;
bool flag;
if (a.f && f) { //同为负数情况--左边-右边==(不看符号)右边-(不看符号)左边
if (compare(a, *this)) {
flag = false;
res = minus(a, *this);
} else {
if (isEqual(*this, a))
flag = false;
else flag = true;
res = minus(*this, a);
}
} else if (a.f && !f) { //左边为正,右边为负--左边-右边==左边+右边
flag = false;
res = add(a, *this);
} else if (!a.f && f) { //右边为正,左边为负--左边-右边==两边为负的加法
flag = true;
res = add(a, *this);
} else { //同时为正数--左边-右边==左边-右边(分类讨论正负
if (compare(a, *this)) { //右边>左边,符号为负
res = minus(a, *this);
flag = true;
} else { //右边<左边,符号为正
res = minus(*this, a);
flag = false;
}
}
res.f = flag;
return res;
}
四、其他内部成员函数详解
- 向外提供的get接口
int getCap() {
return capacity;
}
int getLength() {
return length;
}
bool isNegative() {
return f;
}
bool isEmpty() {
return length == 0;
}
- 进行赋值操作所必备的push_back和reverse函数
void push_back(char x) {
if (length >= capacity) {//扩容操作
capacity *= 2;
char *t = nums;
nums = new char[capacity];
std::copy(t, t + length, nums);
delete[]t;
}
nums[length++] = x;
}
void reverse() {//反转操作
int l = 0, r = length - 1;
while (l < r) {
std::swap(nums[l], nums[r]);
l++;
r--;
}
}
- 无关紧要的
read()
输入接口 和print()
输出测试接口
void print() {
if (f)
printf("-");
nums[length] = '\0';
int i = 0;
while (nums[i] == '0')i++;
printf("%s", nums + i);
}
void read() {//利用getchar()给对象赋上数据
char c = getchar();
if (c == '-') {
f = true;
c = getchar();
}
while (c == '0') c = getchar();//将前导0消耗掉
while (c != '\n') {
push_back(c);//不断的调用push_back即可
c = getchar();
}
}
整理代码
.h声明文件
如果在声明类的同时进行定义,则内部的成员函数默认就是内联的。所以我们一般把短小的代码进行内联,以下的实现均是以该规律进行。
//
// Created by Alone on 2021/10/7.
//
#ifndef MY_TINY_STL_BIGINTEGER_H
#define MY_TINY_STL_BIGINTEGER_H
#include <algorithm>
#include <iostream>
#include <cstring>
class BigInteger {
bool f;
char *nums;
int length;
int capacity;
public:
//构造函数
BigInteger() : length(0), capacity(1), f(false) { //缺省构造函数
nums = new char[capacity];
}
BigInteger(const char *n);
BigInteger(const BigInteger &a);
BigInteger(BigInteger &&a);
~BigInteger() { //析构函数
delete[] nums;
}
public:
//静态函数
static void Swap(BigInteger &a, BigInteger &b);
static bool compare(const BigInteger &a, const BigInteger &b);
bool isEqual(BigInteger &a, BigInteger &b);
static BigInteger add(BigInteger &a, BigInteger &b);
static BigInteger minus(BigInteger &a, BigInteger &b);
public:
//运算符重载
char &operator[](int i) {
return nums[i];
}
BigInteger &operator=(BigInteger &&a) { //Swap&Copy方式实现右值赋值重载
Swap(*this, a);
return *this;
}
BigInteger &operator=(const BigInteger &a);
bool operator<(const BigInteger &a) const;
BigInteger operator+(BigInteger &a);
BigInteger operator-(BigInteger &a);
public:
//对象的基本成员函数
int getCap() {
return capacity;
}
int getLength() {
return length;
}
bool isNegative() {
return f;
}
bool isEmpty() {
return length == 0;
}
void reverse();
void push_back(char x);
void print();
void read();
};
#endif //MY_TINY_STL_BIGINTEGER_H
.cpp定义并实现
//
// Created by Alone on 2021/10/7.
//
#include "BigInteger.h"
//@构造函数实现
BigInteger::BigInteger(const char *n) : length(strlen(n)), f(false) { //用于初始值的构造函数
int start = 0;
if (n[0] == '-') {
f = true;
start++;
}
while (start < length && n[start] == '0')start++;
capacity = length * 10;
nums = new char[capacity];
std::copy(n + start, n + length, nums);
length = length - start;
}
BigInteger::BigInteger(const BigInteger &a) { //拷贝构造函数
capacity = a.capacity;
length = a.length;
f = a.f;
nums = new char[capacity];
std::copy(a.nums, a.nums + length, nums);
}
BigInteger::BigInteger(BigInteger &&a) : length(0) { //移动构造函数
*this = a;
}
//@静态函数实现
void BigInteger::Swap(BigInteger &a, BigInteger &b) {
std::swap(a.length, b.length);
std::swap(a.capacity, b.capacity);
std::swap(a.f, b.f);
std::swap(a.nums, b.nums);
}
bool BigInteger::compare(const BigInteger &a, const BigInteger &b) {
int n1 = a.length;
int n2 = b.length;
if (n1 != n2)return n1 > n2; //返回a和b哪个大,true则位a大
int i = 0;
while (i < n1 && a.nums[i] == b.nums[i])i++; //a b一样长的情况下,比较两个的值
if (i == n1)
return false;
return a.nums[i] > b.nums[i];
}
bool BigInteger::isEqual(BigInteger &a, BigInteger &b) {
if (a.f != b.f || (a.length != b.length))return false;
int i = 0;
while (i < a.length && a.nums[i] == b.nums[i])i++;
return i == a.length && a.f == b.f;
}
BigInteger BigInteger::add(BigInteger &a, BigInteger &b) {
a.reverse();//尾端对齐
b.reverse();
BigInteger t;
int up = 0;
int len = a.length > b.length ? a.length : b.length;
for (int i = 0; i < len; i++) {
int ta = i < a.length ? a[i] - '0' : 0;
int tb = i < b.length ? b[i] - '0' : 0;
int base = ta + tb + up;
t.push_back(base % 10 + '0');
up = base / 10;
}
if (up)
t.push_back(up + '0');
t.reverse();//返回原位
a.reverse();
b.reverse();
return t;
}
BigInteger BigInteger::minus(BigInteger &a, BigInteger &b) {
a.reverse();
b.reverse();
BigInteger t;
int len = a.length > b.length ? a.length : b.length;
for (int i = 0; i < len; i++) {
int ta = i < a.length ? a[i] - '0' : 0;
int tb = i < b.length ? b[i] - '0' : 0;
int base = ta - tb;
if (base < 0) {
base += 10;
a[i + 1]--;
}
t.push_back(base + '0');
}
t.reverse();
a.reverse();
b.reverse();
return t;
}
//@运算符重载实现
BigInteger &BigInteger::operator=(const BigInteger &a) {
if (length != 0)//如果不是初始化调用的 = ,则肯定需要先把原来的内存delete掉
delete[]nums;
capacity = a.capacity;
length = a.length;
f = a.f;
nums = new char[capacity];
std::copy(a.nums, a.nums + length, nums);
return *this;
}
BigInteger BigInteger::operator+(BigInteger &a) {
BigInteger res;
bool flag;
if (a.f && f) { //同为负数情况,直接相加,再改符号
res = add(*this, a);
flag = true;
} else if (a.f && !f) {//左正右负
if (compare(a, *this)) { //看负数对应的nums是否比正数大
flag = true;
res = minus(a, *this);
} else {
flag = false;
res = minus(*this, a);
}
} else if (!a.f && f) {
if (compare(*this, a)) { //与上一个相同
flag = true;
res = minus(*this, a);
} else {
flag = false;
res = minus(a, *this);
}
} else { //同时为正数就是最简单的加法
flag = false;
res = add(*this, a);
}
res.f = flag;
return res;
}
BigInteger BigInteger::operator-(BigInteger &a) {
BigInteger res;
bool flag;
if (a.f && f) { //同为负数情况--左边-右边==(不看符号)右边-(不看符号)左边
if (compare(a, *this)) {
flag = false;
res = minus(a, *this);
} else {
if (isEqual(*this, a))
flag = false;
else flag = true;
res = minus(*this, a);
}
} else if (a.f && !f) { //左边为正,右边为负--左边-右边==左边+右边
flag = false;
res = add(a, *this);
} else if (!a.f && f) { //右边为正,左边为负--左边-右边==两边为负的加法
flag = true;
res = add(a, *this);
} else { //同时为正数--左边-右边==左边-右边(分类讨论正负
if (compare(a, *this)) { //右边>左边,符号为负
res = minus(a, *this);
flag = true;
} else { //右边<左边,符号为正
res = minus(*this, a);
flag = false;
}
}
res.f = flag;
return res;
}
bool BigInteger::operator<(const BigInteger &a) const {
if (f && !a.f) { //其中一个为负数,则那个是更小的
return true;
} else if (!f && a.f)
return false;
if (f) { //两者都为负数的情况,左边的值要更大则为true
return compare(*this, a);
}//两者均为正数,则值更小的在左边为true
return compare(a, *this);
}
//@基本成员函数
void BigInteger::reverse() {
int l = 0, r = length - 1;
while (l < r) {
std::swap(nums[l], nums[r]);
l++;
r--;
}
}
void BigInteger::push_back(char x) {
if (length >= capacity) {
capacity *= 2;
char *t = nums;
nums = new char[capacity];
std::copy(t, t + length, nums);
delete[]t;
}
nums[length++] = x;
}
void BigInteger::print() {
if (f)
printf("-");
nums[length] = '\0';
int i = 0;
while (nums[i] == '0')i++;
printf("%s", nums + i);
}
void BigInteger::read() {
char c = getchar();
if (c == '-') {
f = true;
c = getchar();
}
while (c == '0') c = getchar();//将前导0消耗掉
while (c != '\n') {
push_back(c);//不断的调用push_back即可
c = getchar();
}
}
功能测试
一、基本的加减测试
运行的测试代码: 打印输出 python输出
- 总结
与python输出无异,故通过测试。但碍于测试数据太过少,不是很有说服力,还有后面的解题测试。
二、存储个人输入的数据+排序测试
测试代码(方便测试只输入了10个数据): 排序输出:
三、解题测试
正好最近刷的PAT甲级就涉及到大数的加减hhh! 题目描述 OJ平台
解题代码
#include "bits/stdc++.h"
class BigInteger {
bool f;
char *nums;
int length;
int capacity;
public://构造函数
BigInteger() : length(0), capacity(1), f(false) { //缺省构造函数
nums = new char[capacity];
}
BigInteger(const char *n) : length(strlen(n)), f(false) { //用于初始值的构造函数
int start = 0;
if (n[0] == '-') {
f = true;
start++;
}
while (start < length && n[start] == '0')start++;
capacity = length * 10;
nums = new char[capacity];
std::copy(n + start, n + length, nums);
length = length - start;
}
BigInteger(const BigInteger &a) { //拷贝构造函数
capacity = a.capacity;
length = a.length;
f = a.f;
nums = new char[capacity];
std::copy(a.nums, a.nums + length, nums);
}
BigInteger(BigInteger &&a) : length(0) { //移动构造函数
*this = a;
}
~BigInteger() { //析构函数
delete[] nums;
}
public://静态成员函数
static void Swap(BigInteger &a, BigInteger &b) {
std::swap(a.length, b.length);
std::swap(a.capacity, b.capacity);
std::swap(a.f, b.f);
std::swap(a.nums, b.nums);
}
static bool compare(const BigInteger &a, const BigInteger &b) { //比较纯nums大小(不看符号
int n1 = a.length;
int n2 = b.length;
if (n1 != n2)return n1 > n2; //返回a和b哪个大,true则位a大
int i = 0;
while (i < n1 && a.nums[i] == b.nums[i])i++; //a b一样长的情况下,比较两个的值
if (i == n1)
return false;
return a.nums[i] > b.nums[i];
}
bool isEqual(BigInteger &a, BigInteger &b) {
if (a.f != b.f || (a.length != b.length))return false;
int i = 0;
while (i < a.length && a.nums[i] == b.nums[i])i++;
return i == a.length && a.f == b.f;
}
static BigInteger add(BigInteger &a, BigInteger &b) { //不看符号的加法
a.reverse();//尾端对齐
b.reverse();
BigInteger t;
int up = 0;
int len = a.length > b.length ? a.length : b.length;
for (int i = 0; i < len; i++) {
int ta = i < a.length ? a[i] - '0' : 0;
int tb = i < b.length ? b[i] - '0' : 0;
int base = ta + tb + up;
t.push_back(base % 10 + '0');
up = base / 10;
}
if (up)
t.push_back(up + '0');
t.reverse();//返回原位
a.reverse();
b.reverse();
return t;
}
static BigInteger minus(BigInteger &a, BigInteger &b) { //不看符号的减法,默认了a的长度或者大小是比b要大的(所以外界不要乱调用
a.reverse();
b.reverse();
BigInteger t;
int len = a.length > b.length ? a.length : b.length;
for (int i = 0; i < len; i++) {
int ta = i < a.length ? a[i] - '0' : 0;
int tb = i < b.length ? b[i] - '0' : 0;
int base = ta - tb;
if (base < 0) {
base += 10;
a[i + 1]--;
}
t.push_back(base + '0');
}
t.reverse();
a.reverse();
b.reverse();
return t;
}
public://成员函数和重载运算符
char &operator[](int i) {
return nums[i];
}
BigInteger &operator=(BigInteger &&a) { //Swap&Copy方式实现右值赋值重载
Swap(*this, a);
return *this;
}
BigInteger &operator=(const BigInteger &a) {//深拷贝
if (length != 0)//如果不是初始化调用的 = ,则肯定需要先把原来的内存delete掉
delete[]nums;
capacity = a.capacity;
length = a.length;
f = a.f;
nums = new char[capacity];
std::copy(a.nums, a.nums + length, nums);
return *this;
}
int getCap() {
return capacity;
}
int getLength() {
return length;
}
bool isNegative() {
return f;
}
bool isEmpty() {
return length == 0;
}
void reverse() {
int l = 0, r = length - 1;
while (l < r) {
std::swap(nums[l], nums[r]);
l++;
r--;
}
}
void push_back(char x) {
if (length >= capacity) {
capacity *= 2;
char *t = nums;
nums = new char[capacity];
std::copy(t, t + length, nums);
delete[]t;
}
nums[length++] = x;
}
bool operator<(const BigInteger &a) const {
if (f && !a.f) { //其中一个为负数,则那个是更小的
return true;
} else if (!f && a.f)
return false;
if (f) { //两者都为负数的情况,左边的值要更大则为true
return compare(*this, a);
}//两者均为正数,则值更小的在左边为true
return compare(a, *this);
}
BigInteger operator+(BigInteger &a) {
BigInteger res;
bool flag;
if (a.f && f) { //同为负数情况,直接相加,再改符号
res = add(*this, a);
flag = true;
} else if (a.f && !f) {//左正右负
if (compare(a, *this)) { //看负数对应的nums是否比正数大
flag = true;
res = minus(a, *this);
} else {
flag = false;
res = minus(*this, a);
}
} else if (!a.f && f) {
if (compare(*this, a)) { //与上一个相同
flag = true;
res = minus(*this, a);
} else {
flag = false;
res = minus(a, *this);
}
} else { //同时为正数就是最简单的加法
flag = false;
res = add(*this, a);
}
res.f = flag;
return res;
}
BigInteger operator-(BigInteger &a) {
BigInteger res;
bool flag;
if (a.f && f) { //同为负数情况--左边-右边==(不看符号)右边-(不看符号)左边
if (compare(a, *this)) {
flag = false;
res = minus(a, *this);
} else {
if (isEqual(*this, a))
flag = false;
else flag = true;
res = minus(*this, a);
}
} else if (a.f && !f) { //左边为正,右边为负--左边-右边==左边+右边
flag = false;
res = add(a, *this);
} else if (!a.f && f) { //右边为正,左边为负--左边-右边==两边为负的加法
flag = true;
res = add(a, *this);
} else { //同时为正数--左边-右边==左边-右边(分类讨论正负
if (compare(a, *this)) { //右边>左边,符号为负
res = minus(a, *this);
flag = true;
} else { //右边<左边,符号为正
res = minus(*this, a);
flag = false;
}
}
res.f = flag;
return res;
}
void print() {
if (f)
printf("-");
nums[length] = '\0';
int i = 0;
while (nums[i] == '0')i++;
printf("%s", nums + i);
}
void read() {//利用getchar()给对象赋上数据
char c = getchar();
if (c == '-') {
f = true;
c = getchar();
}
while (c=='\n'||c == '0'||c == ' ') c = getchar();//将前导0消耗掉和空格
while (c != '\n'&&c != ' '&& c != '\t') {
push_back(c);//不断的调用push_back即可
c = getchar();
}
}
};
int main() {
using namespace std;
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
char a[100], b[100], c[100];
printf("Case #%d: ", i);
cin >> a >> b >> c;
BigInteger a1(a), b2(b), c2(c);
BigInteger t = c2 - b2;
if (t < a1)
cout << "true\n";
else cout << "false\n";
}
return 0;
}
正确输出
总结
很多人,可能觉得做项目一定得是那种高大上,又或者是那种贪吃蛇小游戏、扫雷小游戏类型,实际上只要你有兴趣,任何一个东西都能成为你的练手项目,并且收获收获也许比你跟风去弄几个小游戏更大。
做这个小项目,我的收获是,对C++的语法更加的了解了,关于移动构造器、拷贝构造器、赋值重载这块弄得更清楚了,最大的收获在于强化了一个类的设计思路,这个是最重要的。
多写一些类的实现,不仅有利于对算法和语言语法的理解,更大的收获在于对各个功能的设计思路,作为程序员,我们最需要的就是这样的逻辑思维,从接到需求开始,我们应该能迅速的抽象出各种实现方案,然后进行不断的优化,得出属于自己的代码!