• 传统生意免责声明如何做

    做任何的社群营销或者销售任何产品,必须过滤掉一些胡搅蛮缠的人,必须把免责声明做到极致,

    保证所有人,都没办法找到您的漏洞,您的麻烦。

    任何人找您麻烦,过分了,您就可以起诉他。这就是免责声明的威力。我们不是什么人的生意都做。我们每句话都是真话,一味的索取者不是我们的客户群体,我们要找的是有智慧,智力高的人。您必须不断强调您要的客户是什么人,如此,越精准,您越赚钱,而且越具有品牌属性。

    付费后不退费,用完产品不保证每一个人都有效果。写的非常明确。

    讲清楚,自己是知识消费,培训消费,社群消费,由于是虚拟消费,所以不退费。是产品的,可以写明由于每一个人特别性质不同,所以无法保证一样的效果。

    免责声明做得越到位,越正式,资料齐全,公司名称齐全,公章齐全,出单率越高。

  • 传统生意在朋友圈内怎么搞图片

    朋友圈销售的是信任感!而图片是最容易产生信任感的,所谓无图无真相。不管你是做任何生意的,做朋友圈营销图片非常的重要,一张好的图片可以让潜在客户瞬间记住你的产品,你的服务,你的个人品牌,提升对你的信任感。

    1,好的图片都是贴近生活化的东西,贵在用心,我们不管走到哪里,看到好的人、事、物都可以拍照记录下来。我们创业的人生活跟工作其实就是一体的,本来就分不开。

    2,拍一些职业装、或者找个摄影师街拍,做 300 张质量高的图片。人们都喜欢赏心悦目的照片,这样的朋友圈看起来就是生活化而又不缺专业素养。能够更加获得他人的认可。

    3,社群成员聊天的截图、与客户沟通的截图、好的图片内容截图,各种截图。

    4,看到好吃的,好玩的,好看的都拍下来,作为图片素材库。

    5,自己的工作场景,生活化场景都是我们采集图片的对象,女朋友、家人、朋友的合影能出现在朋友圈信任度会更高。

    6,拒绝发布负能量、情绪化的图片。永远发正能量、有价值的图片。

    7、所有的图片上必须有一句广告词阐明你的业务,您的收费标准,您的付费方式,这是最简单也是最基本的营销。

  • 传统生意如何在朋友圈做自动成交?

    微信已经是一种生活方式,不管您是传统生意还是别的任何生意都可以在朋友圈做社群营销,如何通过朋友圈营销做自动成交产品和服务。

    1,自我介绍。朋友圈营销第一要素就是自我介绍,你是谁?你多大?你来自哪里?你是做什么的?你有什么故事?你的创业故事、奋斗故事。

    2,为什么要买你的产品或加入社群。你能提供什么价值和服务,加入社群的好处,比如你做化妆培训的,好处就是有讲课,有老师指导你学习化妆技巧。

    3,定位聚焦关键词。我们必须时刻清楚自己的定位。你是卖什么产品,提供什么服务,应该很清楚,比如说你是卖护肤产品,那你的客户就是注重保养的,那你的内容应该朝这个思路走,我们就要做个护肤专家。如果你提供的是虚拟产品,比如说英语培训,那你的文案图片视频都是围绕这个话题来讲。一定不能做两个以上的环节,比如你做护肤产品的又做英语线上培训,那你的标签属性就不明确,别人不知道你具体是做什么的。聚焦关键词,只做一个内容。

    4,您必须讲真话,每句话都是真的,你的文案、图片、视频全部都要是真实的。杜绝弄虚作假。

    5,朋友圈有您的家人,女朋友,老婆,父母,孩子,朋友,吃饭,您的成交率会更高。

    6,社群聊天图片,客户咨询截图,都要进行传播,对你的社群进行真实描述。比如群里有 500 人,200 人,100 人,进行真实描述。您卖什么,您就实际描述,买什么有什么具体的好处。

    7,广告里必须要有免责声明,也就是出现哪些情况不是您承担的责任,这必须告知您的客户,您的粉丝。免掉一切的麻烦。

    8,设置业务介绍封面背景图,搞一个文字版本的业务介绍,任何人加您,跟您聊天,最多聊三句话,然后就发布这个文字版的广告,图片版如果看得清楚也行,告诉他, 如果想加入社群,跟着老师学,就看看这个。

    9,真正的高手。是通过释放价值做广告,是通过组合拳做广告。一切广告,只针对富人,不针对穷人。针对耿直的人,不要给自己惹麻烦,切记切记,千万不要骗人。

    10,做人态度要极度诚恳,要勤奋,要尊重人,要有爱。

    11,竭尽全力搞外部流量,视频+音频不断的去释放价值吸引到你的朋友圈,不要局限于你身边的那点流量。只有真正认可你内容价值的人才是你的精准客户。

  • 传统项目放弃后做什么项目赚钱?

    项目很多,可以分实体项目、虚拟项目、虚实结合项目。

    很多人从来没想过,通过自媒体这条渠道突显自己的品牌价值、打造个人 IP。展现自己的专业,技能水平,其实只要你能突破自己,踏出第一步,你已经开始赚钱了。若有才华,更佳。

    在互联网上积累粉丝,别人就会为你买单。你看那些抖音上做泡妞的、恋爱的、做英语内容的……,无不是这种套路。

    自媒体转化产品,无论是实体产品还是虚拟产品,其实这都不重要了。重要的是有需求就有市场。

    1,实体项目可以按照我们的方法论,用我们的聚焦系统、30 循环系统、行动力系统去量化考核你的员工工作。

    2,虚拟项目可以选择靠我们社群内部的项目赚钱,创业社群、恋爱社群、微博社群项目都可以做。进相对于的 Vip 社群就可以参与,没有其他的成本。

    3,想继续做传统行业的,直接转型互联网化。用我们的 30 循环系统吸引外部流量,导入到你的微信朋友圈做自动成交。

    4,任何赚钱的项目本质上就是搞流量、做成交,我们提供的是可以直接落地操作的方法,解决流量的问题,成交的问题。

  • 传统实业如何搞合作

    传统生意老板大多是把所有的利润都抓到手里,越是这样越辛苦,越不赚钱。成功的人往往并不是自身能力有多牛逼,而是懂得借力搞合作。不是让自己成为一个巨人,而是站在巨人的肩膀上。

    1,任何生意的本质都是搞流量、做成交。没有流量何谈成交。一个人只要做好一个环节到极致已经很厉害了,其他的就一切外包找合作。

    2,前期做一个项目或者卖一个产品,你可以找合作着谈好分层,把售后或者产品交给别人来做,比如我们每天的任务就是做 30 个视频发出去搞流量,为了聚焦这一个环节疯狂的搞流量,我就把成交售后交给别人来做。

    3,找员工来给你做视频、做售后也算是合作,只是你是发工资给他们,并且还要懂得管理他们,不然他们不会卖力的给你干活。考核他们也是有没有一天完成一个 30 循环系统。所以没有管理能力的人就找有实力的人合作。谈好分层就好了,你会非常轻松。

    4,当你比较有财力后,你的合作系统可以更精细化,比如有专门做视频的、有专门负责搞图片的、有专门负责文案和作品上传的……..

    5,搞合作是为了专注于自己擅长的环节,聚焦做到极致,不是为了当甩手掌柜。完全什么都不做,什么都依靠别人,你会吃大亏。

    6,社会是有分工的,一个人永远干不过一个团队。如果你的团队里面有很多牛逼的合作者,你会变得更牛逼。

    7,传统生意老板还要懂得与自身建立的社群成员合作,让自己客户和粉丝成为您产品的传播者,代理商,而通过您少他多的方式让他们全力以赴为您裂变。

    8,记住,要想赚钱,一定是工作越简单越好,环节越少越好,只抓最有价值的工作,其它一切都是通过分成机制来完成。我们社群的合作是 91 分成,表面上看老师赚得特别少,但是有了影响力和自动传播的裂变,实则得到了很多,而合作者赚取了高利润,这叫各取所需,各作共赢。

  • 传统行业如何线下做流量?

    任何生意亏损或者倒闭本质都是缺少流量,也就是没有客户。传统行业要想在这个时代生存,必须懂得如何通过一些方式方法主动引流,而守株待兔的获客方式无异于坐以待毙。通过以下方法可以为传统实业更好的做线下导流:

    1、通过设置优惠券和会员卡的方式引流。传统实业门店的生意分为引流期,裂变期和锁客期。引流期的活动一定要大,给到客户超出想像的优惠,到店消费赠送优惠券,消费引导办理会员卡,会员卡的设置可用价格锚定效应,锚定一个主推的价格档次,通常是第二个价格阶梯为主推。

    2、社群裂变。前端的大量引流到一定程度,建立微信端社群,社群里设置各种互动,无利团财等,前期建立与粉丝的信任感,驱动粉丝主动传播达到大量裂变粉丝的目的。在些基础上再实现多种方式的盈利,可以从主营业务上延伸出多种盈利点。

    3、异业联盟。通过与一系列与自身所营业务相关的产业进行合作导流,资源共享达到双方共赢的目的。比如服装可以选择与美容美体,鞋类门店合作,餐饮可与水果,超市等实业合作。

    4、招牌款引流。招牌爆款让利,可在一周内设置固定时间段,无利出售或者搭配一些捆绑销售甚至免费等等,根据不同的行业性质来划分,目的是为了人气,记住,所有的实业都是先有流量和人气再有财气。

    5、砸广告。差异化卖点打造,让人过目不忘的广告词非常重要。但这项成本较高,对一些没有财力基础的老板不建议使用。互联网时代免费广告宣传的渠道很多,各位老板在投入的时候务必计算产出。

  • 自媒体如何转化产品

    1,实体项目可以按照我们的方法论,用我们的聚焦系统、30 循环系统、行动力系统去量化考核你的员工工作。

    2,虚拟项目可以选择靠我们社群内部的项目赚钱,创业社群、恋爱社群、微博社群项目都可以做。进相对于的 Vip 社群就可以参与,没有其他的成本。

    3,想继续做传统行业的,直接转型互联网化。用我们的 30 循环系统吸引外部流量,导入到你的微信朋友圈做自动成交。

    4,任何赚钱的项目本质上就是搞流量、做成交,我们提供的是可以直接落地操作的方法,解决流量的问题,成交的问题。

  • 传统项目放弃后做什么项目赚钱?

    项目很多,可以分实体项目、虚拟项目、虚实结合项目。

    很多人从来没想过,通过自媒体这条渠道突显自己的品牌价值、打造个人 IP。展现自己的专业,技能水平,其实只要你能突破自己,踏出第一步,你已经开始赚钱了。若有才华,更佳。

    在互联网上积累粉丝,别人就会为你买单。你看那些抖音上做泡妞的、恋爱的、做英语内容的……,无不是这种套路。

  • 传统实业如何让收入翻几翻

    1、当您一个人能干出月入十万的时候,您要开始用这套方法将项目放大。比如您可以有团队一天有十个人帮您做 30 循环系统。那么您就拥有了原来十倍的流量。

    2、您有一个五百人的社群,您完全搞懂了如何运营互动裂变,您可以用利益交换让群员帮您裂变出第二个,第三个,第十个 500 人的大群,将项目放大。

    3、聚焦一个环节,也就是互联网音频,视频搞流量。

    4、30 循环系统是什么?就是日日 30 个视频,或者音频。

    10 个账号操作,每个账号 3 个视频,或者音频,日日夜夜上传。

  • 传统实业如何为您的产品搞广告

    做任何生意都离不开打广告,你永远都在释放价值,却不告诉别人你在做什么,能提供什么样的产品和服务,那毫无意义。你永远都在说你的产品多好多好,多便宜,只会招来方案甚至屏蔽。谁跳出来都说他的产品特别好特别牛,那我为什么要找你买。其实这个时代不缺好的产品,缺的好的营销广告。

    1,高明的广告是让你看不出来是广告,广告本质是越软越好。观众看得津津有味,看到最后一回味才知道原来是个广告,心里面是佩服是认同,通俗说就是你的内容很有价值感,别人喜欢看,你只是在不起眼的地方恰到好处的留了一句话广告。

    2,我们的广告一定要从内容上下功夫,江小白为什么那么火,就是它的文案内容很牛逼。我们做朋友圈营销也要走这样的模式,永远是好的文案+一句话广告+图片。

    3,好的文案怎么写,就是内容要足够干,没有废话,让别人看了有价值感、有认同感。可以去到各大平台,比如百度搜索相关的素材,改编成自己的。比如你是做护肤的,你就搜护肤小知识,跳出来的内容多得不行,整理好做成一段或一篇文案即可。

    4,一句话话广告怎么写。一句话广告只需要介绍你的产品和服务就可以了,比如说,怕上火喝王老吉、老白金,健康品,年轻态……,但是我们可以更直接一点,你是做化妆社群的,可以写成“付费 500 邀你进 VIP 群学化妆,解决每天化妆的烦恼”。

    5,一句话广告就是加在你优质的文案最后,或者加在优质的图片上就可以了。直接发硬广告是愚蠢的行为。

排序算法深入研究

薪薪向荣 JackLeon 1个月前 (03-19) 65次浏览 0个评论 扫描二维码

堆排序

堆积排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。

堆是具有以下性质的完全二叉树:

  • 每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;
  • 或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。

排序算法深入研究

同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中

该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:

  • 大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
  • 小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

堆排序的最好、最坏、平均时间复杂度都为Ο(nlogn)

步骤:

堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余 n-1 个元素重新构造成一个堆,这样会得到 n 个元素的次小值。如此反复执行,便能得到一个有序序列了

  1. 构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)

假设给定无序序列结构如下:

此时我们从最后一个非叶子结点开始(叶结点自然不用调整,最后一个非叶子结点 arr.length/2-1=5/2-1=1,也就是下面的 6 结点),从左至右,从下至上进行调整

找到第二个非叶节点 4,由于[4,9,8]中 9 元素最大,4 和 9 交换

这时,交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中 6 最大,交换 4 和 6

此时,我们就将一个无需序列构造成了一个大顶堆

  1. 将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换

将堆顶元素 9 和末尾元素 4 进行交换

重新调整结构,使其继续满足堆定义

再将堆顶元素 8 与末尾元素 5 进行交换,得到第二大元素 8

后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序

总结下堆排序的基本思路:

  • 将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
  • 将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
  • 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序

代码实现:

/**
     * 升序(大顶堆)
     * @param array
     * @return
     */
    public static Integer[] asc(Integer[] array) {
        int len = array.length;
        while (len > 1) {
            // 无序数组大顶堆排序
            bigHeapify(array, len);
            // 交换堆顶元素与末尾元素
            swap(array, 0, len - 1);
            len --;
        }
        return array;
    }

    /**
     * 大顶堆
     * @param array
     */
    private static void bigHeapify(Integer[] array, int length) {
        for (int i = length / 2 - 1; i >= 0; i--) {
            int lNode = i * 2 + 1;
            int rNode = i * 2 + 2;
            if(array[i] < array[lNode]){ // 左节点大于父节点时,交换值
                swap(array, i, lNode);
            }
            if(rNode < length && array[i] < array[rNode]){ // 右节点大于父节点时,交换值
                swap(array, i, rNode);
            }
        }
    }
    
    /**
     * 降序(小顶堆)
     * @param array
     * @return
     */
    public static Integer[] desc(Integer[] array) {
        int len = array.length;
        while (len > 1) {
            // 无序数组小顶堆排序
            smallHeapify(array, len);
            // 交换堆顶元素与末尾元素
            swap(array, 0, len - 1);
            len --;
        }
        return array;
    }

    /**
     * 小顶堆
     * @param array
     * @return
     */
    private static void smallHeapify(Integer[] array, int length) {
        for (int i = length / 2 - 1; i >= 0; i--) {
            int lNode = i * 2 + 1;
            int rNode = i * 2 + 2;
            if(array[i] > array[lNode]){ // 左节点小于于父节点时,交换值
                swap(array, i, lNode);
            }
            if(rNode < length && array[i] > array[rNode]){ // 右节点小于于父节点时,交换值
                swap(array, i, rNode);
            }
        }
    }
    
    /**
     * 交换值
     * @param array
     * @param s
     * @param t
     */
    private static void swap(Integer[] array, int s, int t) {
        array[s] = array[s] + array[t];
        array[t] = array[s] - array[t];
        array[s] = array[s] - array[t];
    }

排序效果:

快速排序

介绍:

快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性。

步骤:

  1. 从数列中挑出一个元素,称为 “基准”(pivot),
  1. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  1. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

代码实现:

/**
 * Java
 */

void quickSort(Integer[] array, int left, int right) {
    final int left_ = left;
    final int right_ = right;
    if(left <= right){ 
        int pivot = array[left];    // 取第一个元素为基准
        while(left != right) {
            while (left < right && array[right] >= pivot) right --;
            array[left] = array[right];
            while (left < right &&  array[left] <= pivot) left ++;
            array[right] = array[left];
        }
        array[right] = pivot;    // 集准点归位
        quickSort(array, left_, left - 1);    // 递归左分区
        quickSort(array, right + 1, right_);    // 递归右分区
    }
}

排序效果:


归并排序

介绍:

归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用

步骤:

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
  1. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
  1. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
  1. 重复步骤 3 直到某一指针达到序列尾
  1. 将另一序列剩下的所有元素直接复制到合并序列尾

代码实现:

/**
 * JavaScript
 */

function mergeSort(arr) {  // 采用自上而下的递归方法
    var len = arr.length;
    if(len < 2) {
        return arr;
    }
    var middle = Math.floor(len / 2),
        left = arr.slice(0, middle),
        right = arr.slice(middle);
    return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right)
{
    var result = [];

    while (left.length && right.length) {
        if (left[0] <= right[0]) {
            result.push(left.shift());
        } else {
            result.push(right.shift());
        }
    }

    while (left.length)
        result.push(left.shift());

    while (right.length)
        result.push(right.shift());

    return result;
}

/**
 * Java
 */

public static Integer[] mergeSort(Integer[] array) {
    if(array.length < 2) return array;
    int middle = array.length / 2;
    Integer[] lArr = Arrays.copyOfRange(array, 0, middle);
    Integer[] rArr = Arrays.copyOfRange(array, middle, array.length);
    return sort(mergeSort(lArr), mergeSort(rArr));
}
    
private static Integer[] sort(Integer[] lArr, Integer[] rArr) {
    Integer[] array = new Integer[lArr.length + rArr.length];
    int index = 0;
    int r = 0;
    int l = 0;
    while (index < lArr.length + rArr.length) {
        if(l < lArr.length && r < rArr.length && rArr[r] > lArr[l]){
            array[index] = lArr[l];
            l++;
            index ++;
        }else if(r < rArr.length){
            array[index] = rArr[r];
            r++;
            index ++;
        }else{
            while (index < lArr.length + rArr.length && r < rArr.length){
                array[index] = rArr[r];
                r++;
                index ++;
            }
            while (index < lArr.length + rArr.length && l < lArr.length){
                array[index] = lArr[l];
                l++;
                index ++;
            }
        }
    }
    return array;
}

排序效果:


选择排序

介绍:

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。以此类推,直到所有元素均排序完毕。

步骤:

  1. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
  1. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
  1. 重复第二步,直到所有元素均排序完毕。

代码实现:

/**
 * JavaScript
 */
function selectionSort(arr) {
    var len = arr.length;
    var minIndex, temp;
    for (var i = 0; i < len - 1; i++) {
        minIndex = i;
        for (var j = i + 1; j < len; j++) {
            if (arr[j] < arr[minIndex]) {     // 寻找最小的数
                minIndex = j;                 // 将最小数的索引保存
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    return arr;
}

/**
 * Java
 */
void selectionSort(Integer[] array) {
    for (int i = 0; i < array.length - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < array.length; j++) {
            if(array[minIndex] >= array[j]) minIndex = j;
        }
        if(array[minIndex] == array[i]) continue;
        array[minIndex] = array[minIndex] + array[i];
        array[i] = array[minIndex] - array[i];
        array[minIndex] = array[minIndex] - array[i];
    }
}

排序效果:

冒泡排序

介绍:

冒泡排序(Bubble Sort,台湾译为:泡沫排序或气泡排序)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

步骤:

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  1. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
  1. 针对所有的元素重复以上的步骤,除了最后一个。
  1. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

代码实现:

/**
 * Java
 */

void bubbleSort(Integer[] array) {
    for (int i = 0; i < array.length - 1; i++) {
        for (int j = i + 1; j < array.length; j++) {
            if(array[i] > array[j]){
                array[i] = array[i] + array[j];
                array[j] = array[i] - array[j];
                array[i] = array[i] - array[j];
            }
        }
    }
}

排序效果:

插入排序

介绍:

插入排序(Insertion Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用 in-place 排序(即只需用到 O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

步骤:

  1. 从第一个元素开始,该元素可以认为已经被排序
  1. 取出下一个元素,在已经排序的元素序列中从后向前扫描
  1. 如果该元素(已排序)大于新元素,将该元素移到下一位置
  1. 重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置
  1. 将新元素插入到该位置中
  1. 重复步骤 2

代码实现:

/**
 * JavaScript
 */

function insertionSort(arr) {
    var len = arr.length;
    var preIndex, current;
    for (var i = 1; i < len; i++) {
        preIndex = i - 1;
        current = arr[i];
        while(preIndex >= 0 && arr[preIndex] > current) {
            arr[preIndex+1] = arr[preIndex];
            preIndex--;
        }
        arr[preIndex+1] = current;
    }
    return arr;
}

/**
 * Java
 */

void insertionSort(Integer[] array) {
    for (int i = 1; i < array.length; i++) {
        int current = array[i];
        int prevIndex = i - 1;
        while (prevIndex >= 0 && array[prevIndex] > current) {
            array[prevIndex + 1] = array[prevIndex];
            prevIndex --;
        }
        array[prevIndex + 1] = current;
    }
}

排序效果:

1

希尔排序

2

介绍:

3

4

希尔排序,也称递减增量排序算法,是插入排序的一种高速而稳定的改进版本。

5

6

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

7

8

1、插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率

9

10

2、但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位

11

12

排序效果:

13

14

15

计数排序

介绍:

计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数

计数排序是一个稳定的排序算法。当输入的元素是 n 个 0 到 k 之间的整数时,时间复杂度是 O(n+k),空间复杂度也是 O(n+k),其排序速度快于任何比较排序算法。当 k 不是很大并且序列比较集中时,计数排序是一个很有效的排序算法

步骤:
  1. 找出待排序的数组中最大和最小的元素;
  1. 统计数组中每个值为 i 的元素出现的次数,存入数组 C 的第 i 项;
  1. 对所有的计数累加(从 C 中的第一个元素开始,每一项和前一项相加);
  1. 反向填充目标数组:将每个元素 i 放在新数组的第 C(i)项,每放一个元素就将 C(i)减去 1。

代码实现:

/**
     * 计数排序
     * @param array
     */
    void countingSort(Integer[] array) {
        // 找出最大值、最小值
        int max = array[0];
        int min = array[0];
        for (int i = 1; i < array.length; i++) {
            if(array[i] > max) max = array[i];
            if(array[i] < min) min = array[i];
        }
        // 最大最小元素之间范围[min, max]的长度
        int len = max - min + 1; 
        // 建立辅助数组,记录出现的次数,并初始化(0 次)
        int[] timesOfArray = new int[len + 1];
        for (int i = 0; i < array.length; i++) { 
            // 使用加 1 后的索引,有重复的该位置就自增
            timesOfArray[array[i] - min + 1] ++;
        }
        // 频率 -> 元素的开始索引
        for (int i = 0; i < len; i++) {
            timesOfArray[i + 1] += timesOfArray[i];
        }
        // 元素按照开始索引分类,用到一个和待排数组一样大临时数组存放数据
        int[] aux = new int[array.length];
        for (int i = 0; i < array.length; i++) {
            // 填充一个数据后,自增,以便相同的数据可以填到下一个空位
            aux[timesOfArray[array[i] - min]++] = array[i];
        }
        // 数据回写
        for (int i = 0; i < array.length; i++) {
            array[i] = aux[i];
        }
    }

void countingSort(Integer[] array) {
        // 找出最大值
        int max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(array[i] > max) max = array[i];
        }
        max ++;
        // 建立辅助数组,记录出现的次数,并初始化(0 次)
        Integer[] timesOfArray = new Integer[max];
        for (int i = 0; i < timesOfArray.length; i++) {              // 运算次数  50 < O(n)
            timesOfArray[i] = 0;
        }
        // 遍历 array 数据,记录出现次数
        for (Integer integer : array) timesOfArray[integer] ++;     // 运算次数  100 = O(n)
        // 遍历 timesOfArray,实现 array 排序
        int j = 0;
        for (int i = 0; i < max; i++) {                          
            int times = timesOfArray[i];
            times += j;
            for (;j < times; j++) array[j] = i;                      // 运算次数  100 = O(n)
        }
    }

排序效果:

桶排序

介绍:

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)

桶排序最好情况下使用线性时间 O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为 O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大

步骤:

  1. 设置一个定量的数组当作空桶;
  1. 遍历输入数据,并且把数据一个一个放到对应的桶里去;
  1. 对每个不是空的桶进行排序;
  1. 从不是空的桶里把排好序的数据拼接起来。 

代码实现:
排序效果:

基数排序

介绍:

基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前

基数排序基于分别排序,分别收集,所以是稳定的。但基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要 O(n)的时间复杂度,而且分配之后得到新的关键字序列又需要 O(n)的时间复杂度。假如待排数据可以分为 d 个关键字,则基数排序的时间复杂度将是 O(d*2n) ,当然 d 要远远小于 n,因此基本上还是线性级别的。

基数排序的空间复杂度为 O(n+k),其中 k 为桶的数量。一般来说 n>>k,因此额外空间需要大概 n 个左右

步骤:

  1. 取得数组中的最大数,并取得位数;
  1. arr 为原始数组,从最低位开始取每个位组成 radix 数组;
  1. 对 radix 进行计数排序(利用计数排序适用于小范围数的特点);

代码实现:
排序效果:


温馨提示:若在升级会员或付费后阅读过程中遇到问题,请加客服微信号(cool-smiler)沟通解决,祝您生活愉快。
转载请注明原文链接:排序算法深入研究
喜欢 (0)
[1186664388@qq.com]
分享 (0)
关于作者:
创享视界(creativeview.cn)是一个带动全民颠覆八小时工作制,通过投稿把自己的创意智慧变现的方式创造被动收入,从而实现财务自由的平台。我们相信,创新思维不仅有助于打造更出色的产品,还可以让世界变得更美好,让人人受益。
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
%d 博主赞过: