数据结构与算法分析 第7章总结 排序

插入排序:

插入排序方法为:遍历、抽牌、较大牌后移、放牌。算法复杂度O(N)。

N个互异数的数组的序偶的总个数N(N-1)/2,平均逆序数为其一半N(N-1)/4。

通过交换相邻元素的任何排序算法都需要Omega(N^2)时间。

//**********

public static > void insertSort(AnyType[] a){

                  for(int p=1;p

                                    AnyType eject=a[p];

                                    int j;

                                    for(j=p;j>0&&a[j-1].compareTo(eject)>0;j--)

                                                      a[j]=a[j-1];

                                    a[j]=eject;                                 

                  }

}

//**********

希尔排序:

希尔排序通过比较具有一定间隔的元素来工作,各趟比较的距离逐渐缩小,直到比较相邻元素的最后一趟为止。因此希尔排序又称"缩减增量排序",复杂度O(N^2)。

而Hibbard增量的希尔排序的最坏时间O(N^(3/2))。

//**********

public static > void shellSort(AnyType[] a){

                  for(int gap=a.length/2;gap>0;gap/=2){

                                    for(intp=gap;p

                                                      AnyTypeeject=a[p];

                                                      int j;

                                                      for(j=p;j>0&&a[j-gap].compareTo(eject)>0;j-=gap)

                                                                        a[j]=a[j-gap];//此处注意步进为gap而不是1

                                                      a[j]=eject;

                                    }

                  }

}

//**********

堆排序:

数组二叉堆实现的堆排序:建堆buildHeap耗时O(N),弹堆deleteMin耗时O(logN),总时间O(NlogN)。

堆排序避免拷贝数组耗时O(N)及空间的方法:堆中最后的单元用来存放deleteMin的元素。使用最大堆将得到增排序。


数组二叉堆由下滤perculate、建堆buildHeap、弹堆deleteHeap构成。

[if !supportLists]l [endif]堆排的下滤同快排一样使用半判断循还,区别是堆排并非为了效率,而是需要先处理下滤路径才能做出判断。

下滤三判断:取左子防溢出,比右比防溢出,下滤终止。

[if !supportLists]l [endif]建堆过程就是非叶节点的下滤过程。(叶结点就不必下滤了)

[if !supportLists]l [endif]弹堆过程的取堆根、堆尾补、下滤过程,在堆排序中简化为堆的根尾交换,使堆排序成为了原址排序。

注点1:全部写为静态static函数,不封闭。

注点2:数组中0位置有元素,索引号加1。

注点3:perculateDown(a,end,hole)要注明末元素end用来区分未排数据堆和已排数据。

                  public static intleftChild(int i) {

                                    return 2 * i+ 1; //索引号从1开始才是左儿子2i,右儿子2i+1

                  }

                  public static > void swap(AnyType[] a, int s1,int s2) {

                                    AnyType tmp= a[s1];

                                    a[s1] =a[s2];

                                    a[s2] = tmp;

                  }


                  public static > void perculateDown(AnyType[] a,int end, int hole) {

                                    AnyTypeeject = a[hole];

                                    int child;

                                    for (;; hole= child) {

                                                      child= leftChild(hole);

                                                      if(child > end)

                                                                        break;

                                                      if(child< end && a[child].compareTo(a[child + 1])<0)

                                                                        child++;//向小儿子走(这里为max堆对应向大儿子走)

                                                      if(a[child].compareTo(eject)>0)

                                                                        a[hole]= a[child];

                                                      else

                                                                        break;

                                    }

                                    a[hole] =eject;

                  }


                  public static > void heapSort(AnyType[] a) {

                                    for (int i =a.length / 2; i >= 0; i--)

                                                      perculateDown(a,a.length - 1, i);

                                    for (int end= a.length - 1; end > 0;) {

                                                      swap(a,0, end--);//交换相当于保存了deleteMin元素并且补上了根节点

                                                      perculateDown(a,end, 0);

                                    }

                  }

归并排序

归并排序为典型的递归算法:分治、解决、合并(两副有序牌合为有序排)、递归底为1个元素不用排。

归并排序的合牌方法:双针拣牌,拷贝余牌,拷回临时数组。

归并排序的递归函数形参为待排数组和始末位置。

归并排序的缺点是非原址排序,算法复杂度O(NlogN+N)。

                  public static > void mergeSort(

                                                      AnyType[] a) {

                                    mergeSort(a, 0, a.length - 1);

                  }


                  public static > void mergeSort(

                                                      AnyType[] a,int left, int right) {

                                    if (left < right) {

                                                      int center =(left + right) / 2;

                                                      mergeSort(a,left, center);

                                                      mergeSort(a,center + 1, right);

                                                      merge(a, left,center, right);

                                    }

                  }


                  public static > void merge(

                                                      AnyType[] a,int leftStart, int leftEnd, int rightEnd) {

                                    int itemNum = rightEnd -leftStart + 1;

                                    AnyType[] tmp = (AnyType[]) newObject[itemNum];//泛型数组的创建

                                    int leftPos = leftStart;

                                    int rightPos = leftEnd + 1;

                                    int tmpPos = 0;

                                    while (leftPos <= leftEnd&& rightPos <= rightEnd) {

                                                      if(a[leftPos].compareTo(a[rightPos]) < 0)

                                                                        tmp[tmpPos++]= a[leftPos++];

                                                      else

                                                                        tmp[tmpPos++]= a[rightPos++];

                                    }

                                    while (leftPos <= leftEnd) {

                                                      tmp[tmpPos++] =a[leftPos++];

                                    }

                                    while (rightPos <= rightEnd) {

                                                      tmp[tmpPos++] =a[rightPos++];

                                    }

                                    int copyBackPos = leftStart;

                                    for (int i = 0; i < itemNum;){

                                                      a[copyBackPos++]= tmp[i++];

                                    }


                  }

快速排序:

快速排序算法:

[if !supportLists]1)            [endif]三数中值分割定枢纽元(首末元素已分集,枢纽元置末二位),pivot枢纽。

遇等枢纽值不跳,即实现了非二次时间的可能,又配合"三数中值分割"起到了限界的作用。

2)              分集方法为:初始位让针,无条件跳针(先++助交换跳针),非相遇换针,相遇终止。枢纽元与i针交换。

3)              子问题递归,递归子问题left~i-1,i+1~right

4)              递归底用插排

快速排序复杂度O(NlogN)

快速排序算法要点:

[if !supportLists]l [endif]交换数据元素,swap的形参包含数组引用和2个位置指针。

[if !supportLists]l [endif]快速排序的分集方法采用"半判断循还"while(true){代码;if(条件)代码;elsebreak;},优点是跳针是无条件的,减少了比较次数。

[if !supportLists]l [endif]与枢纽元相等的i,j都不跳针(都停止),这是唯一不花费二次时间的可能。

[if !supportLists]l [endif]N<=20的小数组,快排不如插排,且5个数以下快排不可用。默认递归底cutoff=10。

//**********

                  public static > void swap(

                                                      AnyType[] a,int s1, int s2) {

                                    AnyType tmp = a[s1];

                                    a[s1] = a[s2];

                                    a[s2] = tmp;

                  }


                  public static > AnyType median(

                                                      AnyType[] a,int left, int right) {

                                    int center = (left + right) / 2;

                                    if (a[left].compareTo(a[center])> 0)

                                                      swap(a, left,center);

                                    if (a[left].compareTo(a[right])> 0)

                                                      swap(a, left,right);

                                    if (a[center].compareTo(a[right])> 0)

                                                      swap(a, center,right);

                                    swap(a, center, right - 1);

                                    return a[right - 1];

                  }


                  public static > void quickSort(

                                                      AnyType[] a) {

                                    quickSort(a, 0, a.length - 1);

                  }


                  public static > void quickSort(

                                                      AnyType[] a,int left, int right) {

                                    int cutoff = 10;

                                    if (right - left > cutoff) {

                                                      AnyType pivot =median(a, left, right);//重点:递归的函数要用形参,不要误用常量

                                                      int i = left;

                                                      int j = right -1;

                                                      while (true) {

                                                                        while(a[++i].compareTo(pivot) < 0) {}

                                                                        while(a[--j].compareTo(pivot) > 0) {}

                                                                        if(i < j)

                                                                                          swap(a,i, j);

                                                                        else

                                                                                          break;

                                                      }

                                                      swap(a,i,right-1);

                                                      quickSort(a,left,i-1);

                                                      quickSort(a,i+1,right);


                                    } else {// cutoff个数以下用插排

                                                      for (int p =left+1; p <=right; p++) {//注意right处有值,因而p<=right

                                                                        AnyTypeeject = a[p];

                                                                        intj;

                                                                        for(j = p; j > left && a[j - 1].compareTo(eject) > 0; j--)

                                                                                          a[j]= a[j - 1];

                                                                        a[j]= eject;

                                                      }

                                    }


                  }

//**********]


快速选择算法以O(N)时间解决选择问题(N个数中第k个最大值)

[if !supportLists]l [endif]三数中值分割选枢纽元:三数排序、并将枢纽元置末2位。

作用:选枢纽元、预分集两个数、防止出界。

[if !supportLists]l [endif]分集方法(半判断循还):初始针让位、无条件跳针、非相遇换针、相遇退出。交换针i与枢纽元。

[if !supportLists]l [endif]递归子问题:在大理大、在小理"减大集数减1"地大。

k<=S2元素数递归quikSelect(S2,k);k=S2元素数+1返回枢纽元;k> S2元素数+1递归quickSelect(S1,k-S2元素数-1)。

[if !supportLists]l [endif]递归底

快选与快排的区别仅是,快选只是单边递归子问题。

快选代码:

biggerNum=right-i;

if(k<=biggerNum)

                  quickSelect(a,i+1,right,k);

else if(k>right-i+1)

                  quickSelect(a,left,i-1,k-biggerNum-1);

else

                  return;


区别:插排前插,选排后选,向上相邻冒泡。复杂度都是O(N^2)。

补充选择排序

选择排序:外内双针,内针向后遍历,遇到更小则交换(共双循还)。

                  public static void selectSort(int[] a){

                                    for(int i=0;i

                                                      for(intj=i+1;j

                                                                        if(a[i]>a[j])

                                                                                          swap(a[i],a[j]);

                  }


补充冒泡排序:外层正序遍历,内层逆序遍历,冒泡相邻元素。

                  public static void bubbleSort(int[] a){

                                    for(int i=0;i

                                                      for(intj=a.length;j>=0;j++)

                                                                        if(a[j-1]>a[j])

                                                                                          swap(a[j-1],a[j]);

                  }


补充桶排序:。以元素值为桶索引进行装桶,拷回原数组。桶排快于快排却极耗空间,仅适用于小整数。复杂度O(M+N),M为桶大小。

                  public static void bucketSort(int[] a,intmaxNumber){

                                    int[] bucket=new int[maxNumber];

                                    for(int i=0;i

                                                      bucket[a[i]]=a[i];

                                    int writeBackPos=0;

                                    for(inti=0;i

                                                      if(bucket[i]>0)//待排数组不含整数0

                                                                        a[writeBackPos++]=bucket[i];

                  }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,313评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,369评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,916评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,333评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,425评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,481评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,491评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,268评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,719评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,004评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,179评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,832评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,510评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,153评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,402评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,045评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,071评论 2 352

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,743评论 0 33
  • 在浙江出差,天气炎热。 路遇去普陀山给菩萨进香的民众,为其虔诚之心所感。 本周敬献《心经》原文,有缘同学可放进心里...
    Rose海洋阅读 423评论 0 1
  • 很不錯的一張照片. 因為歐洲杯的關係.再加上購物打折季節..為防止有暴徒.在各大賣場.景點.都安排了這些士兵巡邏.
    Jupiler阅读 153评论 0 0
  • 聚光灯下,我正给一班学生上作文课,课题是“物象的选择与运用”。孩子们的眼睛很纯净,我上得也投入,甚至忘记台下...
    徐飞阅读 652评论 1 3