Blog


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 日程表

  • 站点地图

  • 公益404

  • 搜索

编程思想

发表于 2020-01-06 | 分类于 理论 | 阅读次数:
字数统计: 677

一:介绍POP

  1. POP:Procedure Oriented Programming (面向过程)

  2. 理论介绍:Pop是一个面向过程的编程,事件比较简单,可以用线性的思维去解决问题。

  3. 通俗的讲:就是按照事情的发展顺序去执行。

  4. 图解:

    1578320005995

  5. 怎么把大象放进冰箱?
  • 打开冰箱
  • 把大象放进冰箱
  • 关上冰箱
那么,请问如果把猫放进冰箱了?
  1. 打开冰箱
  2. 把大象拿出来
  3. 把猫放进去
  4. 关上冰箱

优势:

  • 流程化使得编程任务明确,在开发之前基本考虑了实现方式和最终结果;
  • 效率高,面向过程强调代码的胆小精悍,善于结合数据结构来开发高效率的程序;
  • 流程明确,具体步骤清楚,便于节点分析。

劣势:

  • 需要深入的思考,耗费精力,代码重用性低,扩展能力差,维护起来难度比较高;
  • 对复杂业务来说,面向过程的模块话难度较高,耦合度也比较高。

二:介绍OOP

  1. OOP:Object Oriented Programming (面向对象)
  2. 理论介绍:OOP是考虑问题的方式,可以应对复杂的业务需求。
  3. 通俗的讲:面向对象针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。
  4. 图解:

1578322238885

5.解决POP的不能扩展的问题,编写复杂的业务逻辑。

优势:

  • 结构清晰,程序便于模块化,结构化,抽象化,更加符合人类的思维方式;
  • 封装性,将事务高度抽象,从而便于流程中的行为分析,也便于操作和自省;
  • 容易扩展,代码重用率高,可继承,可覆盖;
  • 实现简单,可有效地减少程序的维护工作量。

缺点:

  • 面向对象在面向过程的基础上高度抽象,从而和代码底层的直接交互非常少,从而不适合底层开发和游戏开发,甚至是多媒体开发;
  • 复杂性,对于事务开发而言,事务本身是面向过程的,过度的封装导致事务本身的复杂性提高。

二:介绍AOP

  1. AOP:Aspect Oriented Programming (面向切面)
  2. 理论介绍:通过预编译方式和运行期动态代理实现程序功能的中统一处理业务逻辑的一种技术。
  3. 通俗的讲:面向切面,把程序某些模块都要执行的方法,提取出来,写一个方法,在使用的地方,只需要调用就行了!比较常见的场景是:日志记录,错误捕获、性能监控等。
  4. 图解:

1578323216643

Github查询方式

发表于 2019-12-27 | 阅读次数:
字数统计: 65

一:Github的搜索方法

  1. in:name [name]:通过名称搜索
  2. in:name [name] start:>[3000]:通过名称+星数
  3. in:readme [name]:通过rd介绍查询
  4. in:description [name] language:[java] pushed:>2019-09-03:通过md搜索,语言搜索,更新上传时间搜索

Socket

发表于 2019-12-10 | 分类于 Socket | 阅读次数:
字数统计: 919

一:介绍一下Socket

程序之间的通讯,使用Socket来连接处理数据,就是一种协议。

1575988667401

二:Socket相关概念

端口:可以认为是设备与外界通讯交流的出口。

IP:又译为网际协议或互联网协议,是用在TCP/IP协议簇中的网络层协议。

协议:TCP/UDP

TCP UDP
速度 慢 快
是否连接 面向连接(3次握手) 无连接
传输可靠性 安全稳定,效率低 速度快、效率高,不稳定
数据量 少量 大量

三次握手:

(1)在建立通道时,客户端首先要向服务端发送一个SYN同步信号。

(2)服务端在接收到这个信号之后会向客户端发出SYN同步信号和ACK确认信号。

(3)当服务端的ACK和SYN到达客户端后,客户端与服务端之间的这个“通道”就会被建立起来。

三:Socket通信基本流程图

1575989299190

四:代码演示

1.首先我们编写服务器代码,创建负责通讯的Socket绑定对应的IP和端口号,然后进行监听。

1
2
3
4
5
6
7
8
9
10
//创建负责通讯的Socket
socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(txt_IP.Text);
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txt_port.Text));
//获得要连接的远程服务器应用程序的IP地址和端口号
socketSend.Connect(point);
ShowMsg("连接成功!");
//开启线程不断接受信息
Thread t2 = new Thread(Recive);
t2.Start();

2.接受客户端发送的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/// <summary>
/// 轮询接受信息
/// </summary>
/// <param name="o"></param>
void Recive()
{
while (true)
{
try
{
byte[] buffer = new byte[1024 * 1024 * 3];
int r = socketSend.Receive(buffer);
int n = buffer[0];
if (r == 0)
{
break;
}
//发送文字消息
if (n == 0)
{
//实际接收到的有效字节数
string str = Encoding.UTF8.GetString(buffer, 1, r-1);
ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + str);

}
else if (n == 1)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.InitialDirectory = @"C:\Users\Administrator\Desktop";
sfd.Title = "请选择要保存的文件";
sfd.Filter = "所有文件|*.*";
sfd.ShowDialog(this);
string path = sfd.FileName;
using (FileStream fs=new FileStream(path,FileMode.OpenOrCreate,FileAccess.Write))
{
fs.Write(buffer,1,r);
}
}
else if(n==2)
{
ZD();
}


}
catch (Exception)
{
throw;
}
}
}

3.编写客户端:

首先得创建一个Socket对象负责通讯,然后绑定和服务器同一个IP和端口,然后和服务器进行连接。

1
2
3
4
5
6
7
8
9
10
//创建负责通讯的Socket
socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(txt_IP.Text);
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txt_port.Text));
//获得要连接的远程服务器应用程序的IP地址和端口号
socketSend.Connect(point);
ShowMsg("连接成功!");
//开启线程不断接受信息
Thread t2 = new Thread(Recive);
t2.Start();

4.客户端轮询接受服务器的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/// <summary>
/// 轮询接受信息
/// </summary>
/// <param name="o"></param>
void Recive()
{
while (true)
{
try
{
byte[] buffer = new byte[1024 * 1024 * 3];
int r = socketSend.Receive(buffer);
int n = buffer[0];
if (r == 0)
{
break;
}
//发送文字消息
if (n == 0)
{
//实际接收到的有效字节数
string str = Encoding.UTF8.GetString(buffer, 1, r-1);
ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + str);

}
else if (n == 1)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.InitialDirectory = @"C:\Users\Administrator\Desktop";
sfd.Title = "请选择要保存的文件";
sfd.Filter = "所有文件|*.*";
sfd.ShowDialog(this);
string path = sfd.FileName;
using (FileStream fs=new FileStream(path,FileMode.OpenOrCreate,FileAccess.Write))
{
fs.Write(buffer,1,r);
}
}
else if(n==2)
{
ZD();
}


}
catch (Exception)
{
throw;
}
}
}

5.可以进行验证客户机和服务器是否连接成功:

1575990142459

左边是客户端,右边是服务器。

6.客户端和服务端发送信息

1
2
3
        string str = txt_send.Text.Trim();
byte[] buffer = Encoding.UTF8.GetBytes(str);
socketSend.Send(buffer);

1575990451173

7.源码地址

C#-泛型

发表于 2019-11-28 | 阅读次数:
字数统计: 337

一:介绍泛型

​ 泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念。C#2.0之后出现泛型。

二:实例讲解

1.Object类型是一切类型的父类

2.通过继承,子类拥有父类的一切属性和行为;任何父类出现的地方,都可以用子类来代替

1
2
3
4
public static void ShowObject(object obj)
{
Console.WriteLine("This is {0},parameter={1},type={2}", typeof(ComonMethed), obj.GetType().Name, obj);
}

泛型:使用一个方法,满足不同参数类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   static void Main(string[] args)
{
object a = "123";
int i = 5;
string j = "6";
bool flag = true;
ComonMethed.Show<int>(i);
ComonMethed.Show<string>(j);
ComonMethed.Show<bool>(flag);
}
public class ComonMethed
{

public static void Show<T>(T obj)
{
Console.WriteLine("This is {0},parameter={1},type={2}", typeof(ComonMethed), obj.GetType().Name, obj.ToString());
}
}

1574910783041

网站合集

发表于 2019-11-26 | 阅读次数:
字数统计: 246
  • 高清壁纸搜索引擎 Awesome Wallpapers
  • 稿定设计智能抠图在线PS 稿定设计
  • 抠图AI神器 remove.bg
  • 在线弹钢琴 自由钢琴
  • 免费PDF转换器 Smallpdf
  • 免费在线文件转换器 office-converter
  • 图片压缩神器 TinyPNG
  • 阿里巴巴矢量图标库 iconfont
  • 云端超级应用空间 uzer.me
  • 免费图片上传外链服务 路过图床
  • 一款由阿里团队打造的OCR产品 读光OCR
  • GIF录制工具 screentogif
  • 在线运行C#代码 try.dot.net
  • MSDN, 我告诉你 msdn.itellyou.cn
  • 无版权免费图片站 pixabay
  • 在线音频视频转换器 media
  • 代码图片美化工具 carbon.now.sh
  • 百度云资源搜索引擎 云盘精灵
  • 一站式搜索视频内容的追剧神器 Neets
  • 跨平台云笔记工具 notion
  • 免费教程网站
  • 片吧
  • 免费在线制图
  • [慢慢游社区](https://mmy.la/forum.php
  • Web Servicrs
  • 在线获取时间戳
  • JS在线加密
  • Leetcode

基数排序

发表于 2019-11-25 | 分类于 数据结构 | 阅读次数:
字数统计: 340

一:基数排序(桶排序)介绍:

1574689896893

基数排序基本思想:

1574690002482

图文说明:

1574690131194

二:思想分析

1574690459936

1574690489690

1574690519996

三:代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
static void Main(string[] args)
{
int[] arr = { 34, 75, 489, 9, 123, 3 };
radixSort(arr);
print(arr);
Console.ReadKey();
}

//基数排序方法
public static void radixSort(int[] arr)
{
int[,] bucket = new int[10, arr.Length];
int[] bucketElementCounts = new int[10];

#region 去数组中的长度最长的数
int max = 0;
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] > max)
{
max = arr[i];
}
}
max = max.ToString().Length;
#endregion

for (int m = 0, n = 1; m < max; m++, n *= 10)
{
#region 按照遍历的顺序,将数存入桶中,个位,十位...
for (int i = 0; i < arr.Length; i++)
{
//取出每个元素的个位
int digitOfElement = arr[i] / n % 10;
//放入对应的桶
bucket[digitOfElement, bucketElementCounts[digitOfElement]] = arr[i];
bucketElementCounts[digitOfElement]++;
}
#endregion

#region 遍历桶,将数据重新写会数组汇中
int index = 0;
//遍历每一个桶
for (int i = 0; i < bucketElementCounts.Length; i++)
{
//如果桶有数据,我们才放到原数据中
if (bucketElementCounts[i] != 0)
{
//循环该桶
for (int k = 0; k < bucketElementCounts[i]; k++)
{
//取出元素放入arr
arr[index++] = bucket[i, k];
}
}
bucketElementCounts[i] = 0;
}
#endregion
}
}
/// <summary>
/// 打印
/// </summary>
/// <param name="arr"></param>
public static void print(int[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
Console.Write(arr[i] + "\t");
}
Console.WriteLine("");
}

四:源码地址

Github-基数排序

归并排序

发表于 2019-11-25 | 分类于 数据结构 | 阅读次数:
字数统计: 608

一:归并排序介绍

​ 归并排序是利用归并的思想实现的排序的方法,该算法采用经典的分治策略(分治法将问题分成一些小的问题后递归求解,而治的阶段则将分的阶段得到的各答案“修补”在一起,即分而治之。)

归并排序思想示意图–基本思想:

1574686033954

归并排序思想示意图2 合并相邻有序子序列

1574686834750

二:代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
static void Main(string[] args)
{
int[] arr = {8,4,5,7,1,3,6,2 };
int[] temp = new int[arr.Length];
mergeSort(arr,0,arr.Length-1,temp);
print(arr);
Console.ReadKey();
}
public static void print(int[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
Console.Write(arr[i] + "\t");
}
Console.WriteLine("");
}
/// <summary>
/// 归并排序
/// </summary>
/// <param name="arr">原始数组</param>
/// <param name="left">左边有序序列的初始索引</param>
/// <param name="mid">中间索引</param>
/// <param name="right">右边索引</param>
/// <param name="temp">临时数组</param>
public static void merge(int[] arr,int left,int mid,int right,int[] temp)
{
int i = left;//左边初始化索引
int j = mid + 1;//初始化j,右边初始化索引
int index = 0;//指向temp当前索引

//1.先把左右两边(有序)的数据按照规则填充到temp数组
//直到左右两边的有序序列,有一边处理完毕为止
while (i<=mid&&j<=right)
{
//如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
//就把左边的插入临时数组,i需要后移,index后移
if (arr[i]<=arr[j])
{
temp[index] = arr[i];
index += 1;
i += 1;
}
else
{
temp[index] = arr[j];
index += 1;
j += 1;
}

}

//2.把有剩余数据的一边的数据依次全部填充到temp
while (i<=mid)
{
temp[index] = arr[i];
i+=1;
index+=1;
}
while (j <= right)
{
temp[index] = arr[j];
j+=1;
index+=1;
}

//3.将temp数组的元素拷贝到arr
//注意,并不是每次都拷贝所有
index = 0;
int templeft = left;
while (templeft<=right)
{
arr[templeft] = temp[index];
index += 1;
templeft += 1;
}
}
public static void mergeSort(int[] arr, int left, int right, int[] temp)
{
if (left<right)
{
int mid = (left + right) / 2;
//向左递归
mergeSort(arr,left,mid,temp);
//向右递归
mergeSort(arr, mid+1, right, temp);
//到合并
merge(arr,left,mid,right,temp);
}
}

三:源码地址

Github–归并排序

快速排序

发表于 2019-11-25 | 分类于 数据结构 | 阅读次数:
字数统计: 399

一:介绍快速排序

​ 快速排序是对冒泡排序的一种改进。基本思想:通过一趟排序将要排序的数据分割成独立的两个部分,其中一部分的所有数据都比另外一部分的所有数据要小,然后在按此方法对着两部分分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

快速排序示意图:

1574645960887

二:思路分析

1574646290341

三:代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public static void quickSort(int[] arr,int left,int right)
{
int l = left;//左下标
int r = right;//右下标
int temp = 0;
//prvot 中轴值
int prvot = arr[(l + r) / 2];
//while循环的目的是让比prvot值小的左,比它大的放右边
while (l<r)
{
//在prvot左边一直找,找到大于等于provt值,才推出
while (arr[l]<prvot)
{
l += 1;
}
//在prvot右边一直找,找到大于等于provt值,才推出
while (arr[r] > prvot)
{
r -= 1;
}
//[如果条件成立,prvot的左右两的值,已经按照左边全部是]
if (l>=r)
{
break;
}
//交换
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
//如果交换完,arr[l]==pivot值相等,前移
if (arr[l]==prvot)
{
r -= 1;
}
//如果交换完,arr[r]==pivot值相等,后移
if (arr[r] == prvot)
{
l += 1;
}
}
//如果l==r,必须l++,r--,否则会出现栈溢出
if (l==r)
{
l+=1;
r-=1;
}
//向左递归
if (left<r)
{
quickSort(arr,left,r);
}
//向左递归
if (right >l)
{
quickSort(arr, l, right);
}
}

四:源码地址

Github-快速排序

希尔排序

发表于 2019-11-24 | 分类于 数据结构 | 阅读次数:
字数统计: 400

一:希尔排序的介绍

希尔排序是 简单插入排序改进之后的一个更高效的版本,也称缩小增量排序。

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序:随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰好被分成一组,算法便终止。

希尔排序法的示意图:

1574606940341

二:希尔排序法应用实例:

1574607075654

三:代码实现

1.交换法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static void shellSort(int[] arr)
{
int temp = 0;
int len = arr.Length;
int count = 0;
//
for (int num = len / 2; num >0; num/= 2)
{
for (int i = num; i < arr.Length; i++)
{
for (int j = i - num; j >= 0; j -= num)
{
if (arr[j] > arr[j + num])
{
temp = arr[j];
arr[j] = arr[j + num];
arr[j + num] = temp;
}
}
}
count++;
Console.WriteLine("这是第{0}次排序", count);
print(arr);
}
}

2.移位法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static void shellSort2(int[] arr)
{
//希尔排序的第一论
//因为第一轮排序,是将10个数据分成5组,
int temp = 0;
int len = arr.Length;
int count = 0;
//将数组除2取分组的个数
for (int num = len / 2; num > 0; num /= 2)
{
//组队的值进行比较,满足条件就交换
for (int i = num; i < arr.Length; i++)
{
int j = i;
temp = arr[j];
if (arr[j]<arr[j-num])
{
//移位
while (j-num>=0&& temp<arr[j-num])
{
arr[j] = arr[j - num];
j -= num;
}
arr[j] = temp;
}
}
count++;
Console.WriteLine("这是第{0}次排序", count);
print(arr);
}
}

1574609365704

四:源码地址

Github-希尔排序源码

插入排序

发表于 2019-11-22 | 分类于 数据结构 | 阅读次数:
字数统计: 526

一:插入排序介绍

插入式排序属于内部排序法,是对于欲排序的元素以插入的方式找寻该元素的是的位置,以达到排序的目的。

二:插入排序法思想:

​ 插入排序的基本思想:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将他插入到有序表中的适当位置,使之成为新的有序表。

1574413326358

三:代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
static void Main(string[] args)
{
//int[] arr = { 101,34,119,1};
//insertSort(arr);
int len = 1000;
int[] arrs = new int[len];
for (int i = 0; i < len; i++)
{
Random random = new Random();
int a = (int)random.Next(0, len);
arrs[i] = a;
Thread.Sleep(1);
}
DateTime date1 = DateTime.Now;
Console.WriteLine("插入排序前的时间是" + date1.ToString("HH:mm:ss fff"));
insertSort(arrs);
DateTime date2 = DateTime.Now;
TimeSpan time = date2 - date1;
Console.WriteLine("插入排序后的时间是" + date2.ToString("HH:mm:ss fff"));
Console.WriteLine("插入排序:{0}个数据所用的时间:{1}", len, time.TotalMilliseconds);
}
//插入排序
public static void insertSort(int[] arr)
{
for (int i = 1; i <arr.Length; i++)
{
//第一轮:=>{34,101,119,1}
//定义待插入的数
int inservalue = arr[i];
int index = i - 1;//即arr[1]的前面这个数的下标

//index>=0:保证在inservalue找插入位置,不越界
//inservalue<arr[index]:待插入的数,还没有找到插入的位置
//arr[index]后移
while (index >= 0 && inservalue < arr[index])
{
arr[index + 1] = arr[index];
index--;
}
//当退出while循环时,说明插入的位置找到index+1
arr[index + 1] = inservalue;
// Console.Write("第{0}轮插入:",i);
// print(arr);
}
}
public static void print(int[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
Console.Write(arr[i]+"\t");
}
Console.WriteLine("");
}

1574421922008

想比较插入和冒泡的执行速度:

四:源码地址

Github拆入排序源码

12…6

张聪

60 日志
6 分类
11 标签
© 2020 张聪
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4
总访客 人 总访问量 次