阅读更多

 

来源:GitBook

作者:jack

 

1. 关于排序

很高兴与大家一起探讨计算机科学中的基础算法之排序算法。排序算法是非常基础同时又应用非常广泛的算法,无论在工作还是在生活中,比如:

  • 数据库脚本,如MSSql, MySql, NoSql 中按多个关键词的升序或降序排序,例如,学生按照考试分数排名次,分数相等的再按照学号排序。
  • 前端界面和后端写服务时经常要调用排序接口。
  • 计算机科学很多算法都是基于排序算法的,例如二分查找算法实现逻辑中一般都会先对原序列应用排序操作。
  • 还有很多其他应用.......

2. JAVA中Sort()实现解析

在JAVA中,Sort这个排序函数是如何实现的呢?或许我们在工作学习中,对于如此底层的API,很少去想它是怎么实现的,只是拿来使用它。但是,你可能会有兴趣知道它的神秘面纱。现在让我们认识下它,这个Sort函数结合了我们接下来要讨论的几种排序算法。从这个入口了解常用的排序算法,或许是不错的方法,让我们开启研究排序算法的旅程吧!

2-1 实现思路

Java的Sort函数,按照对象是基本类型和引用类型,将排序算法分为两类实现。对于基本类型,排序算法使用了插入排序和快速排序两种算法的结合;而对于对象是引用类型的,主要使用了归并排序算法。

2-2 为什么结合了三种排序算法?

排序算法的选择主要考虑哪些因素?如果想清楚了这个问题,JAVA中按照如上的实现思路也就清楚了。主要考虑如下因素:

  • 算法的执行效率
  • 排序的稳定性
  • 排序元素的个数
  • 排序关键码的类型
  • 递归调用的开销

首先根据关键码的类型选择排序算法,当为基本类型时,排序实现逻辑如下:

  • 待排序的数组中的元素个数小于 7 时,采用插入排序 (不用快排是因为递归开销代价更大);
  • 当待排序的数组中的元素个数大于 或等于7 时,采用快速排序,选择合适的划分元是极为重要的:
    • 当数组大小 7<size<=40 时,取首、中、末 三个元素中间大小的元素作为划分元;
    • 当数组大小 size>40 时 ,从待排数组中较均匀的选择9个元素,选出一个伪中数做为划分元。

当为引用类型时,排序实现逻辑如下:

  • 采用的是归并排序,为什么,因为对于引用类型排序的稳定性非常重要,而快速排序是无法保证排序的稳定性的,但是归并排序是稳定的排序算法,并且时间复杂也为nlog(n) 。

接下来先介绍JAVA的排序算法中用到的这三个排序:插入排序,快速排序,归并排序。

2-3 插入排序

直接插入排序,英文名称 straight insertion sort,它是一种依次将无序区的元素在有序区内找到合适位置依次插入的算法。

2-3-1 基本思想

每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序,直到无序表内所有元素插入为止。首先在当前有序区R[0..i-1]中查找R[i]的正确插入位置 k(0≤k≤i-1);然后将R[k..i-1]中的记录均后移一个位置,腾出 k 位置上的空间插入R[i]。

2-3-2 插入排序举例

用待排序列 3 2 5 9 2 ,演示直接插入排序的过程,至此结束插入排序的过程,可以看到直接插入排序共经过4轮的操作。

enter image description here

enter image description here

2-3-3 插入排序评价

插入排序的最坏时间复杂度为 O(n^2),属于稳定排序算法,对于处理小批量数据时高效,因此JAVA在排序元素个数小于7时,选择了这种算法。

2-4 快速排序

快速排序(Quicksort)是对冒泡排序的一种改进。

2-4-1 基本思想

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小。然后再按此方法对这其中一部分数据进行快速排序,这是递归调用。再按此方法对另一部分数据进行快速排序,这也是递归调用。

2-4-2 算法介绍

设要排序的数组是A[0]……A[n-1],首先任意选取一个数据作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。一趟快速排序算法所完成的工作:

  1. 设置两个变量 i、j,排序开始的时候:i=0,j=n-1;
  2. 以第一个数组元素作为关键数据,赋值给 pivot,即 pivot =A[0];
  3. 从 j 开始向前搜索,即由后开始向前搜索(j--),找到第一个小于 pivot 的值A[j],将 A[j] 和 A[i] 互换(互换保证了 A[j] < A[i],也就是保证了要趋向于前方的关键码都小于 pivot );
  4. 从 i 开始向后搜索,即由前开始向后搜索(i++),找到第一个大于pivot 的A[i],将 A[i] 和 A[j] 互换(互换保证了 A[j] < A[i],也就是保证了后方的关键码都大于 pivot ) 重复第3、4步,直到 i=j 。
  5. 完成本轮比较

2-4-3 快速排序例子

假设待排序的序列仍为:3 2 5 9 2 。第一轮比较,选取第一个关键码 3 为pivot,初始值 i =0, j =4,整个的比较过程如下图所示:

enter image description here

2-4-4 快速排序评价

快速排序的最坏时间复杂度为 O(n^2),这是一种退化的情况,在大多数情况下只要选取了合适的划分元后,时间复杂度为 nlog(n),快速排序通常比其他 Ο (n log n) 算法更快,属于非稳定排序算法。

2-5 归并排序

归并排序,英文名称是MERGE-SORT。它是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

2-5-1 二路归并

比较 a[i] 和 b[j] 的大小,若 a[i]≤b[j],则将第一个有序表中的元素 a[i] 复制到 r[k] 中,并令 i 和 k 分别加上1;否则将第二个有序表中的元素b[j]复制到 r[k] 中,并令 j 和 k 分别加上1;如此循环下去,直到其中一个有序表取完;然后再将另一个有序表中剩余的元素复制到 r 中从下标 k 到下标 t 的单元。 这个过程,请见下面的例子演示。

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

2-5-2 归并算法

归并排序的算法我们通常用递归实现。先把待排序区间 [s,t] 以中点二分;接着把左边子区间排序;再把右边子区间排序;最后把左区间和右区间用一次归并操作合并成有序的区间 [s,t] 。

2-5-3 递归过程

待排序列 3 2 5 9 2 。下图演示的是归并排序递归版,第一次执行二路归并时的示意图,注意观察右图的栈的入栈顺序。

可以看到 sort 的入栈顺序,当执行一次 merge 时,一定是有2个sort返回并有序了,如下图,sort[0,0]和sort[1,1](递归返回的条件是start<end)都返回了,然后执行到merge,执行完 merge 后,sort[0,1]出栈,此时的栈顶为 sort[0,2] 函数,可以看出它的前半部分已经计算完,只需要计算后半部分,即第二个 sort,然后再次merge,再 sort[0,2] 出栈。。。

enter image description here

如下为上个例子的归并排序的完整示例,sort 和 merge 的示意图,可以看到最后一次merge,正是上面说到的二路 [2,3,5] 和 [2,9] 的归并排序,如果不熟悉的,可以回过头再看看。

enter image description here

2-5-4 归并排序评价

归并排序的最坏时间复杂度为O(nlogn) ,是一种稳定排序算法。

3. JAVA中Sort()为什么没选择如下算法?

以上我们介绍了JAVA中Sort()的主要实现逻辑,那么为什么没有引用其他常见的排序算法呢?像希尔排序算法,冒泡排序,选择排序和堆排序呢?下面我们试着找找原因。

3-1 希尔排序

缩小增量排序,是以上介绍的插入排序算法的一种更高效的改进版本,可以看做是分组版插入排序算法。

3-1-1 希尔排序思想

先取一个正整数 d1<n,把所有序号相隔 d1 的数组元素放一组,组内进行直接插入排序,然后取 d2< d1,重复上述分组和直接插入排序操作;直至 di = 1,即所有记录放进一个组中排序为止。

3-1-2 希尔排序举例

仍然用待排序列 3 2 5 9 2 。在第一轮中,选取增量为2,即分为两组,第一组为 [3 5 2] ,另一组为 [2 9 ] ,分别对这两组做直接插入排序,第一组插入排序的结果为[2 3 5],第二组不动,这样导致的直接结果是原来位于最后的2经过第一轮插入排序后,跑到最头里了,这样两个2的相对位置发生改变了,所以希尔排序不是稳定的排序算法。

再经过第二轮排序,此时的增量为1,所以一共只有一组了,相当于直接插入排序,9后移1步,5插入到原9的位置。

这样整个的希尔排序结束,得到如下图所示的非降序序列。

enter image description here

3-1-3 希尔排序评价

希尔排序的最坏时间复杂度为 O(n^2), 对中等大小规模表现良好,但对规模非常大的数据排序不是最优选择,并且如上所述希尔排序不是稳定的排序算法,所以JAVA弃用它也是再所难免的。

3-2 冒泡排序

JAVA中使用的快排是在冒泡排序的基础上的改进,而冒泡排序一般都是我们最先接触的排序算法,英文名称是 bubble sort 。

3-2-1 冒泡排序思想

已知一组无序数据a[0]、a[1]、……a[n-1],需将其用冒泡排序按升序排列。

首先比较a[0]与a[1]的值,若a[0]大于a[1]则交换两者的值,否则不变,以此类推,最后比较a[n-2]与a[n-1]的值。这样处理一轮后,a[n-1]的值一定是这组数据中最大的。

再对a[0]~a[n-2]以相同方法处理一轮,则a[n-2]的值一定是a[0]~a[n-2]中最大的。

以此类推,这样共处理 n-1 轮后a[0]、a[1]、……a[n-1]就以升序排列了。

3-2-2 冒泡排序举例

待排序列 3 2 5 9 2

  • 第一轮
    • 第1次比较 2 3 5 9 2
    • 第2次比较 2 3 5 9 2
    • 第3次比较 2 3 5 9 2
    • 第4次比较 2 3 5 2 | 9
  • 第二轮
    • 第5次比较 2 3 5 2 9
    • 第6次比较 2 3 5 2 9
  • 第7次比较 2 3 2 | 5 9

  • 第三轮

    • 第8次比较 2 3 2 5 9
    • 第9次比较 2 2 | 3 5 9
  • 第四轮
    • 第10次比较 2 | 2 3 5 9

3-2-3 冒泡排序评价

算法的时间复杂度为 O(n^2),对于大批量数据处理效率低,所以JAVA弃用也是再所难免,是稳定的排序算法。

3-3 选择排序

直接选择排序,英文名称 :Straight Select Sorting,是一个直接从未排序序列选择最值到已排序序列的过程。

3-3-1 选择排序思想

  • 第一次从R[0]~R[n-1]中选取最小值,与R[0]交换;
  • 第二次从R[1]~R[n-1]中选取最小值,与R[1]交换,....,
  • 第 i 次从R[i-1]~R[n-1]中选取最小值,与R[i-1]交换,.....,
  • 总共通过n-1次,得到一个按关键码从小到大排列的有序序列。

3-3-2 选择排序举例

待排序列 3 2 5 9 2。演示如何用直接选择排序得到升序序列。

  • 第一轮,从所有关键码中选择最小值与 R[0]交换,3与2交换,如下图所示,
  • 第二轮,从 R[1]~R[n-1]中选择最小值与R[1]交换,3与2交换;
  • 第三轮,从 R[2]~R[n-1]中选择最小值与R[2]交换,5与3交换;
  • 第四轮,从 R[3]~R[n-1]中选择最小值与R[3]交换,9与5交换;
  • 终止。

enter image description here

3-3-3 选择排序评价

直接选择排序的最坏时间复杂度为 O(n^2) ,效率低也是JAVA不使用它的原因,与处理小批量数据时,直接选择排序所需要的比较次数也比直接插入排序多。它是稳定排序算法。

3-4 堆排序

堆排序,英文名称 Heapsort,利用二叉树(堆)这种数据结构所设计的一种排序算法,是一种对直接选择排序的一种改建算法。在逻辑结构上是按照二叉树存储结构,正是这种结构优化了选择排序的性能,在物理存储上是连续的数组存储,它利用了数组的特点快速定位指定索引的元素。

3-4-1 堆排序思想

以大根堆排序为例,即要得到非降序序列:

  • 先将初始文件R[0..n-1]建成一个大根堆,此堆为初始的无序区。
  • 再将关键字最大的记录R[0](即堆顶)和无序区的最后一个记录R[n-1]交换,由此得到新的无序区 R[0..n-2] 和有序区 R[n-1],且满足 R[0..n-2] ≤ R[n-1] 。由于交换后新的根R[0]可能违反堆性质,故应将当前无序区R[0..n-2]调整为堆。
  • 然后再次将R[0..n-2]中关键字最大的记录R[0]和该区间的最后一个记录R[n-2]交换,由此得到新的无序区R[0..n-3] 和 有序区R[n-2..n-1],且仍满足关系R[0..n-3] ≤ R[n-2..n-1]。
  • 重复步骤2和步骤3,直到无序区只有一个元素为止。

3-4-2 堆排序举例

待排序列 3 2 5 9 2 。第一步,首先以上待排序列的物理存储结构和逻辑存储结构的示意图如下所示:

enter image description here

构建初始堆是从length/2 - 1,即从索引1处关键码等于2开始构建,2的左右孩子等于9, 2,它们三个比较后,父节点2与左孩子9交换,如下图所示:

enter image description here

接下来从索引1减1等于0处,即元素3开始与其左右孩子比较,比较后父节点3与左孩子节点9交换,如下所示:

enter image description here

因为索引等于 0 了,所以构建堆结束,得到大根堆,第一步工作结束,下面开始第二步调整堆,也就是不断地交换堆顶节点和未排序区的最后一个元素,然后再构建大根堆,下面开始这步操作,交换栈顶元素9(如上图所示)和未排序区的最后一个元素2,如下图所示,现在排序区9成为了第一个归位的。

enter image description here

接下来拿掉元素9,未排序区变成了2,3,5,2,然后从堆顶2开始进行堆的再构建,比较父节点2与左右子节点3和5,父节点2和右孩子5交换位置,如下图所示,这样就再次得到了大根堆。

enter image description here

再交换堆顶5和未排序区的最后一个元素2,这样5又就位了,这样未排序区变为了2,3,2,已排序区为 5,9,交换后的位置又破坏了大根堆,已经不再是大根堆了,如下图所示:

enter image description here

所以需要再次调整,然后堆顶2和左孩子3交换,交换后的位置如下图所示,这样二叉树又重新变为了大根堆,再把堆顶3和此时最后一个元素也就是右孩子2交换。

enter image description here

接下来再构建堆,不再赘述,见下图:

enter image description here

3-4-3 堆排序评价

堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,堆排序的最坏时间复杂度是O(nlogn) ,堆排序是不稳定的排序方法。由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的排序序列。

为了防止有人使用精心构造的数据来攻击排序算法,有些框架的排序算法会采取先快速排序,如果发现明显退化迹象,则回退到堆排序这样的时间复杂度稳定的排序上,所以堆排序对基本数据类型排序也是很有用的。

3-5 基数排序

在此由于篇幅问题,不再详细介绍,请参考我在微信公众号中的介绍:基数排序

4. 算法兑现

当我们详细研究了这些常用排序算法的基本实现原理之后,是时候写出这些排序算法的源代码了,也许这些代码在网上有更高效的实现,不过下面写的这些都是和之前说的算法原理和图都解密切相关,一 一对应的,主要是方便大家的理解。

几个算法中使用的一个交换函数,源码如下,

//swap element at i to at j
private static void swap(int[] array, int i,int j){
   int tmp = array[i];
   array[i] = array[j];
   array[j] = tmp;
}

以下排序算法都实现了序列的非降序排列,函数参数代表的含义一般统一定义为:

  • array: 待排序的数组,类型为一维整形数组
  • n:元素个数
  • i:一般为外层循环索引,或表示排序区或未排序的开始或结束索引
  • j :一般为内层循环索引,或表示未排序区或排序的结束或开始索引
  • lo:数组计算区间的开始索引
  • hi:数组计算区间的结束索引
  • d :分组长度
  • k:分组索引

4-1 冒泡排序源码

冒泡排序源码

4-2 快速排序源码

快速排序源码

4-3 插入排序源码

插入排序源码

4-4 希尔排序源码

希尔排序源码

4-5 选择排序源码

选择排序源码

4-6 堆排序源码

堆排序源码

下面列出堆排序的实现代码。注意大根堆顶与未排序区的最后一个元素不断交换,直至未排序区的个数为0,整个序列完成排序。

堆排序算法比较容易出错的点:

构建堆函数,左右子节点可能都有,也可能只含有左节点;

堆排序函数,while遍历时,buildHeap参数中元素个数每次减1,始终从位置0(堆顶)开始调整。

    //heap sort
    public static void heapSort(int[] array, int n){    
        for (int i = n / 2 - 1; i >= 0; i--)
            buildHeap(array, n, i);
        int len = n - 1;
        while (len > 0) {           
            swap(array, 0, len);
            buildHeap(array, len, 0);
            len--;
        }
    }
    private static void buildHeap(int[] array, int n, int i){
        for (; left(i) < n; i = left(i)) {
            int bigger =
                right(i) < n ? max(array, left(i), right(i)) : left(i);
            if (array[bigger] > array[i]) //swap
                swap(array, bigger, i);
            else break;
        }
    }

private static int left(int i){
    return 2*i+1;
}
private static int right(int i){
    return 2*i+2;
}
private static int max(int[] array, int i, int j){
    return array[i]>array[j]? i:j;
}

4-7 归并排序源码

归并排序源码

5. 外部排序

以上阐述的这些都是内部排序, 指的是待排序记录存放在计算机存储器中进行的排序过程。但是,另一类是外部排序, 指的是待排序记录的数量很大,以至于内存一次不能容纳全部记录,在排序过程中尚需对外存进行访问的排序过程。

5-1 多路归并排序

外部排序最常用的算法是多路归并排序,即将原文件分解成多个能够一次性装入内存的部分分别把每一部分调入内存完成排序。然后,对已经排序的子文件进行归并排序。

由于受话题篇幅长度的限制,我们在此不再展开对外部排序的讨论,以后有时间,我们再一起交流。

6. 致谢

以上是我个人对内部排序算法的一些理解,如有分析不准确之处,还请大家多包涵,谢谢大家的参与和讨论!

来自: gitbook
4
0
评论 共 1 条 请登录后发表评论
1 楼 somefuture 2017-12-04 13:22
 

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • C# 邮件服务器

    C# 开发的邮件服务器 Features supports pop3 smtp imap etc. supports ssl/tls for pop3, smtp and imap. supports multi mail vitural server, can bind multi domains. supports run as windows service, winform application with or without tray icon control. supports remote management using mailservermanager.exe supports mail recycle bin supports plugins using api interfaces Build and release download source code or use the releases i provided. if from source code you should run afterbuild.bat after build the solution successfuly then you get the debug or release version from application folder. Installation run MailServerLauncher.exe to install as windows service or just run as desktop application with or without tray icon. Configuration run MailServerManager.exe at the machine runs mailserver service or app. Connect to server press connect button from menu. type server localhost or 127.0.0.1 or leave it empty type username Administrator with case sensitive type password emtpy press ok to connect with saving or not Add virtual server type name and select storage api [your vitural server]>system>general, add dns servers for query mailto's domain mx record. [your vitural server]>system>services, enable smtp and pop3 services and set ipaddress binding with or without ssl/tls. the host name is required when set bindings. eg. bind smtp service to smtp.[your.domain] + IPAddress.Any [your vitural server]>system>service>relay, 'send email using DNS' and set at least a local ipaddress binding for email sending. the name of the binding here only a name,not mean domain. [your vitural server]>system>logging, enable logging for all services when something error you can see the details from 'Logs and Events' node [your vitural server]>domains, set email host domain, eg. if your email will be xyz@abc.com then the domain should be abc.domain, description is optional [your vitural server]>security, !!! important, add rules for your service to allow outside access like email client. eg. add a rule 'Smtp Allow All' for smtp service with ip allows between 0.0.0.0 to 255.255.255.255 to enable smtp service for outside access add 'Pop3 Allow All' and 'Rlay Allow All' like that too. [your vitural server]>filters, there are two types of filter named 'DnsBlackList' and 'VirusScan' its configurable by run it's executable from mail server install path. Domain name resolution Add smtp.[your.domain], pop3.[your.domain], imap.[your.domain] resolution to your server public ip address with A record or to your server domain with CNAME record. mx record is optional if [your.domain] has a A record.if not, you shoud add a mx record point to your server ip. Remote management to enable remote management you must add ACL to allow mail server managers connect from outside network. use MailServerAccessManager.exe to add management users or just use administrator. add rules to allow access from specific IPs or ip ranges The users here only for management cases.

  • ASP.NET:邮件服务器与客户端

    目录: 一、概述 二、MX设置 三、使用系统的SMTP功能发邮件 四、使用hMailServer收发邮件 五、Web邮件客户端 一、概述 首先必须清楚SMTP才是提供邮件服务器的核心,收发邮件全靠SMTP。不信你关掉hMailServer的POP3和IMAP,服务器照样可以收发邮件。POP3和IMAP只是邮件服务器实现的用于提供邮件客户端收取和管理邮件的两种协议,其中POP3协议只能...

  • 详解asp.net邮件收发系统

    详解asp.net邮件收发系统 通过邮件客户端,不需要登录邮箱网站我们就能直接收发邮件。 1 系统分析 邮件收发是各个网站几乎必备的功能,在用户注册、邮箱确认、邮箱客服、找回密码等环节有典型应用。但是在上述例子中,基本都是用的邮件发送的功能,而邮件接收并管理的功能应用的相对较少。而且.NET 平台目前内置的完善的邮件接收的方法还是个空白。 使用一个邮箱服务器挂靠在Live.com上,域名为shuiqu.com的邮箱,实现邮件的收发。 1.1.1 系统目标 本系统需要实现的目标有以下5点。 ⑴ 实现邮件发

  • 开源.NET邮件服务器

    LumiSoft Mail Server是一个开源,免费的邮件服务器,能运行在.net/mono上,支持SMTP/POP3/IMAP4/WebMail,支持MS Sql Server/PostgreSql/Xml等数据存储方式.很适合中小型企业使用,稳定性和兼容性上都没什么问题。 1、基于Microsoft .Net2.0平台,系统更加稳定。2、提供可扩展的接口. 可以与应用无缝

  • 推荐一篇好文章,如何构建.NET邮件服务器

    The Serverside .Net上有一篇介绍如何用.NET技术构建邮件服务器的文章,值得一读。记得自己原来写过的那个SMailer(C++ Wrapped Classes For Mail Sending),所以看到这篇文章就觉得很亲切,不少内容当时我都有所涉及,只是所用技术不同而已。 轻松驾驭Socket — 一个简单的.NET电子邮件服务器(Riding on Sockets - A S

  • C#毕业设计——基于C#+asp.net+cs的Web Mail邮件收发系统设计与实现(毕业论文+程序源码)——邮件收发系统

    大家好,今天给大家介绍基于C#+asp.net+cs的Web Mail邮件收发系统设计与实现,文章末尾附有本毕业设计的论文和源码下载地址哦。文章目录: 项目难度:中等难度 适用场景:相关题目的毕业设计 配套论文字数:8808个字20页 包含内容:整套源码+完整毕业论文 资源文件目录简图如下: 提示:以下为毕业论文的简略介绍,项目源码及完整毕业论文下载地址见文末。引言 省略因此,本设计在脚本中调用.NET框架中System.Web.Mail命名空间,结合HTML完成邮件发送的开发与设计实现。1.1 选题意义

  • .NET的几种开源的邮件组件,你用过那种?

    .NET Core的邮件组件你用过哪些呢?MailKit吗?其实还有。下面是收集github中开源的邮件组件,感兴趣的童鞋可以点击链接去看看详细使用说明。1、FluentEmail:电子邮件发送库。FluentEmail是一款在GitHub上开源免费的支持.Net和.Net Core邮件发送组件,有两个接口“FluentEmail.Core和FluentEmail.Smtp”,第一个是...

  • ASP.NET MVC 5之邮件服务器与客户端

    一、概述 首先必须清楚SMTP才是提供邮件服务器的核心,收发邮件全靠SMTP。不信你关掉hMailServer的POP3和IMAP,服务器照样可以收发邮件。POP3和IMAP只是邮件服务器实现的用于提供邮件客户端收取和管理邮件的两种协议,其中POP3协议只能收取服务器上的邮件,而IMAP协议可供客户端管理服务器上的邮件。目前几乎所有的第三方服务器的SMTP都限制了发送配额等各种限制,并且几乎所有的邮件服务器都会检测发送方的域名和IP是否匹配。简单说就是别用第三方的进行测试,也别用自建的locahost发邮件测试,到底怎么测试呢?在非服务器环境下的邮件发送测试,有3种方案: (1)模拟邮件的发送

  • 创建基于MailKit和MimeKit的.NET基础邮件服务

    邮件服务是一般的系统都会拥有和需要的功能,但是对于.NET项目来说,邮件服务的创建和使用会较为的麻烦。.NET对于邮件功能提供了System.Net.Mail用于创建邮件服务,该基础服务提供邮件的基础操作,并且使用也较为的简单。对于真正将该功能使用于项目的人,就会慢慢发现其中的优缺点,甚至有些时候不能忍受其中的问题。在这里介绍一种微软用于替代System.Net.Mail的...

  • net core邮件服务器,C#发送电子邮件(SMTP)及outlook.com账号之概要

    这是关于c#发送电子邮件(SMTP)的技术笔记,以”简报“形式呈现。因为最后成功通过outlook.com发送了邮件,所以,我觉得还是有必要记录一下其中的要点。一、技术核心.net Framework提供的两个类:SmtpClient和MailAddress前者负责连接到服务器并且发送邮件,后者构成邮件的内容。详细请参考:二、多个接收人观察网易邮箱,多个接收人使用的是分号(【,】)分割,但是直...

  • smtp4dev-用于开发和测试的假smtp电子邮件服务器-.NET开发

    适用于Windows,Linux,Mac OS-X(以及可能提供.NET Core的其他地方)的虚拟SMTP服务器。 使您可以测试应用程序,而不会向实际客户发送垃圾邮件,而无需使用特殊配置来设置复杂的真实电子邮件服务器。 smtp4dev-用于开发和测试的伪造的SMTP电子邮件服务器。 适用于Windows,Linux,Mac OS-X(以及可能提供.NET Core的其他地方)的虚拟SMTP服务器。 使您可以测试应用程序,而不会向实际客户发送垃圾邮件,而无需使用特殊配置来设置复杂的真实电子邮件服务器。 可以查看和检查smtp4dev中收到的消息。 如果您正在寻找旧的Windows GUI v2版本。 在这里抓住它。 如果您发现smtp4dev有用,请注意

  • 搭建邮件服务器,过程非常简单

    搭建邮件服务器,过程非常简单,只需几个步骤即可。通常在Linux搭建邮件服务器是需要安装很多软件和配置文件的,所以我们可以使用一个开源邮件服务器软件来搭建的。

  • C#邮件服务器MailServer(源程序)

    我的商业源程序论坛:www.bzcode.net C#邮件服务器MailServer(源程序) 包含:MailServer,Net,NetHelp,UI 采用C#开发 呵,不得多见的哟

  • asp.net 邮件服务器,用asp.net设计高效邮件列表_邮件服务器

    <%@ Page Language=”VB” Debug=”True” Explicit=”True”%><%@ Import Namespace=”System.Data” %><%@ Import Namespace=”System.Data.OleDb” %><%@ Import Namespace=”System.Web.Mail” %><%@ Import Namespace=”Syst...

  • 如何搭建属于自己的邮件服务器

    申请了属于自己的域名,并且建立了网站,如果您还在您的网站上留下的联系email地址是QQ邮箱或者163以及其它的邮箱地址,这对你网站品牌是多么不好的影响啊,因此您需要搭建一个属于自己的邮件服务器,有了属于自己的邮件服务器后,可以有很多用处,用途举例如下: 别人在您网站注册会员时,发送邮件验证 电子邮件推广,国外还是很流行通过email营销(有被标记为垃圾邮件风险) 您可以随时增加邮箱地址,用...

  • .net程序通过SSL加密服务器发送邮件,

    一、先判断本地网路是否可以登录网页版邮件,这是大前提,可能邮箱服务器有网络限制或者是公司网络有屏蔽。如果ping不通别着急,可能邮箱服务器禁ping 二、网络没问题后就用程序发邮件,看下代码,普通非SSL和安全加密就差一个api //创建邮件对象        MailMessage MyMail = mail;  //是否Html格式邮件 MyMail.IsBodyHtml = true...

Global site tag (gtag.js) - Google Analytics