zoukankan      html  css  js  c++  java
  • 数据结构学习第二十三天

    13:50:24 2019-09-14

    继续把未看完的看完

     13:19:50 2019-09-15

    补上了归并的非递归算法

     16:10:24 2019-09-17

    补上了 堆排序的精明版本

    排序算法

    定理:任意$N$个不同元素组成的序列平均具有$N(N-1)/4$个逆序对

    定理:任何仅以交换相邻两元素来排序的算法,其平均时间复杂度为$Ω(N^2)$

    这样子 冒泡排序 插入排序 的最坏情况都是 N^2

    要使排序算法变高效 得使用间隔元素来交换 在一次排序中 交换多个逆序对的元素

    希尔排序

    定义增量序列$D_M>D_{M-1}>...>D_1=1$

    $对每个D_k进行“D_k-间隔”排序(k=M,M-1,...1)$

    $注意:“D_k-间隔"有序的序列,在执行”D_{k-1}间隔“排序后,仍然是“D_k-间隔"有序的$

    如果增量元素不互质,则小增量可能根本不起作用

    比如 $N=N/2$ 最坏情况 时候 $T= heta(N^{2})$

    那么就会有其他的增量序列:

      Hibbard增量序列 $D_k=2^k-1$  --相邻元素互质  最坏情况$T= heta(N^{3/2})$

      猜想 Hibbard增量的 平均复杂度 $T_{avg}=O(N^{5/4})$

      Sedgewick增量序列 $ {1,5,19,41,109,.....}$

      $9*4^i-9*2^i或4^i-3*2^i+1$猜想$T_{avg}=O(N^{7/6})  T_{worst}=O(N^{4/3})$

    归并排序的时间复杂度为$O(NlogN)$ 该算法是稳定的

    冒泡排序 插入排序 希尔排序 选择排序 堆排序 归并排序(递归与非递归) (ps:其中堆排序写的是憨憨版本 之后会添上精明版本)

      1 #define _CRT_SECURE_NO_WARNINGS  
      2 #include<stdio.h>
      3 #include<malloc.h>
      4 void Print(int A[], int N)
      5 {
      6     for (int i = 0; i < N; i++)
      7         printf("%d ", A[i]);
      8     printf("
    ");
      9 }
     10 //排序算法
     11 
     12 //冒泡排序   //最好 O(N) 最坏 O(N^2)  算法稳定
     13 void Swap(int A[], int i, int j)
     14 {
     15     int temp = A[i];
     16     A[i] = A[j];
     17     A[j] = temp;
     18 }
     19 void Bubble_Sort(int A[], int N)
     20 {
     21     for (int i = 0; i < N; i++)
     22     {
     23         int IsSwap = 0;
     24         for (int j = 0; j < N - i-1; j++)
     25         {
     26             if (A[j] > A[j + 1])
     27             {
     28                 IsSwap = 1;
     29                 Swap(A, j, j + 1);
     30             }
     31         }
     32         if (!IsSwap)
     33             break;
     34     }
     35 }
     36 
     37 //插入排序  //最好O(N) 最坏 O(N^2)  算法稳定
     38 void Insert(int A[], int j, int i) 
     39 {
     40     int temp = A[i];
     41     for (; i > j; i--)
     42         A[i] = A[i - 1];
     43     A[j] = temp;
     44 }
     45 void Insert_Sort(int A[], int N)
     46 {
     47     /*for (int i = 0; i < N-1; i++)
     48     {
     49         int m = i + 1;
     50         int j = i;
     51         while (j >= 0 && A[j] > A[m])
     52             j--;
     53         Insert(A, j+1, m);
     54     }*/
     55     /*for (int i = 1; i < N; i++)
     56     {
     57         int temp = A[i];
     58         int j;
     59         for (j = i - 1; j >= 0 && A[j] > temp; j--)
     60             A[j + 1] = A[j];
     61         A[j + 1] = temp;
     62     }*/
     63     for (int p = 1; p < N; p++)
     64     {
     65         int temp = A[p];
     66         int i;
     67         for (i = p; i > 0 && A[i - 1] > temp; i--)
     68             A[i] = A[i - 1];
     69         A[i] = temp;
     70     }
     71 }
     72 
     73 //希尔排序  //最坏情况  //改进插入排序
     74 void Shell_Sort(int A[], int N)
     75 {
     76     /*for (int D = N / 2; D > 0; D /= 2)
     77     {
     78         for (int p = D; p < N; p++)
     79         {
     80             int temp = A[p];
     81             int i;
     82             for (i = p; i >= D && A[i - D] > temp; i -= D)
     83                 A[i] = A[i - D];
     84             A[i] = temp;
     85         }
     86     }*/
     87     // 利用Sedgewick增量序列
     88     int Si;
     89     int Sedgewick[] = { 929,505,209,109,41,19,5,1,0 };
     90     for (Si = 0; Sedgewick[Si] >=N; Si++)  //初始的增量Sedgewick[Si]不能超过待排序序列长度
     91         ;
     92     for (int D = Sedgewick[Si]; D>0;D=Sedgewick[++Si])
     93     {
     94         for (int p = D; p < N; p++)
     95         {
     96             int temp = A[p];
     97             int i;
     98             for (i = p; i >= D && A[i - D] > temp; i -= D)
     99                 A[i] = A[i - D];
    100             A[i] = temp;
    101         }
    102     }
    103 }
    104 
    105 //选择排序
    106 void Selection_Sort(int A[], int N)
    107 {
    108     for (int i = 0; i < N; i++)
    109     {
    110         int MinPosition = i;
    111         int Min = A[i];
    112         int j;
    113         for (j = i + 1; j < N; j++)
    114         {
    115             if (A[j] < Min)
    116             {
    117                 MinPosition = j;
    118                 Min = A[j];
    119             }
    120         }
    121         Swap(A, i, MinPosition);
    122     }
    123 }
    124 
    125 //堆排序  //选择排序的一种改进
    126 //改进了寻找最小元的算法 利用最小堆来实现
    127 typedef struct HeapStruct* MinHeap;
    128 struct HeapStruct
    129 {
    130     int* Elements;
    131     int Size;
    132     int Capacity;
    133 };
    134 MinHeap Create(int MaxSize)
    135 {
    136     MinHeap H = (MinHeap)malloc(sizeof(struct HeapStruct));
    137     H->Elements = (int*)malloc(sizeof(int) * (MaxSize + 1));
    138     H->Capacity = MaxSize;
    139     H->Size = 0;
    140     H->Elements[0] = -10001;
    141     return H;
    142 }
    143 MinHeap H = Create(20);
    144 //建立最小堆
    145 void PrecDown(MinHeap H, int i)  //下滤
    146 {
    147     int Parent, Child;
    148     int Tmp = H->Elements[i];
    149     for (Parent = i; Parent * 2 <= H->Size; Parent = Child)
    150     {
    151         Child = Parent * 2;
    152         if ((Child != H->Size) && (H->Elements[Child] > H->Elements[Child + 1]))
    153             Child++;
    154         if (Tmp <= H->Elements[Child])break;
    155         else
    156             H->Elements[Parent] = H->Elements[Child];
    157     }
    158     H->Elements[Parent] = Tmp;
    159 }
    160 void BuildMinHeap(MinHeap H)
    161 {
    162     int i;
    163     for (i = H->Size / 2; i > 0; i--)
    164         PrecDown(H, i);
    165 }
    166 int DeleteMin(MinHeap H)
    167 {
    168     int Parent, Child;
    169     int MinItem, temp;
    170     MinItem = H->Elements[1];
    171     temp = H->Elements[H->Size--];
    172     for (Parent = 1; Parent * 2 <= H->Size; Parent = Child)
    173     {
    174         Child = Parent * 2;
    175         if (Child != H->Size && H->Elements[Child] > H->Elements[Child + 1])
    176             Child++;
    177         if (H->Elements[Child] >= temp)break;
    178         else
    179             H->Elements[Parent] = H->Elements[Child];
    180     }
    181     H->Elements[Parent] = temp;
    182     return MinItem;
    183 }
    184 
    185 //利用最大堆实现堆排序 (升序)
    186 void Precdown(int A[], int i, int N)
    187 {
    188     int Parent, Child;
    189     int Tmp;
    190     Tmp = A[i];
    191     for (Parent = i; (Parent * 2) + 1 <= N; Parent = Child)
    192     {
    193         Child = (Parent * 2) + 1;
    194         if (Child != N && A[Child] < A[Child + 1])
    195             Child++;
    196         if (A[Child]<=Tmp)break;
    197         else
    198             A[Parent] = A[Child];
    199     }
    200     A[Parent] = Tmp;
    201 }
    202 void BuildMaxHeap(int A[], int N)
    203 {
    204     for (int i = (N - 1) / 2; i >= 0; i--)
    205         Precdown(A, i, N - 1);
    206 }
    207 
    208 void Heap_Sort(int A[], int N)   
    209 {
    210     //算法一 利用最小堆
    211     /*int Tmp[10] = { 0 };
    212     for (int i = 0; i < 10; i++)
    213         Tmp[i] = DeleteMin(H);
    214     for (int i = 0; i < 10; i++)
    215         A[i] = Tmp[i];*/
    216 
    217     /*for (int i = 0; i < 10; i++)
    218         A[i] = DeleteMin(H);*/
    219     //算法二 利用最大堆后 再调整
    220     BuildMaxHeap(A, N);
    221     //之后调整最大堆
    222     for (int i = N - 1; i >= 0; i--)
    223     {
    224         Swap(A, 0, i);
    225         Precdown(A, 0, i - 1);
    226     }
    227 }
    228 
    229 //归并排序
    230 //递归算法
    231 void Merge(int A[],int lo,int mi,int hi)
    232 {
    233     //两个有序序列的合并
    234     int* B = (int*)malloc(sizeof(int) * (mi - lo));
    235     for (int i = 0; i < mi - lo;i++)B[i] = A[lo + i];
    236     int i, j, k; 
    237     i = lo;
    238     j = 0;
    239     k = mi;
    240     /*while (j<mi-lo||k<hi)
    241     {
    242         if((j<mi-lo)&&(k>=hi||B[j]<=A[k]))A[i++]=B[j++];
    243         if ((k < hi) && (j >= mi-lo|| B[j] > A[k]))A[i++] = A[k++];
    244     }*/
    245     //化简版
    246     while (j<mi-lo)
    247     {
    248         if (k >= hi || B[j] <= A[k])A[i++] = B[j++];
    249         if (k<hi && B[j]>A[k])A[i++] = A[k++];
    250     }
    251     /*邓公版本*/
    252     /*int* A1= A + lo;
    253     int* B = (int*)malloc(sizeof(int) * (mi - lo));
    254     for (int i = 0; i < mi - lo; B[i] = A1[i++]);
    255     int* C = A + mi;
    256     int i, j, k;
    257     for (i = j = k = 0; j < mi - lo || k < hi-mi;)
    258     {
    259         if (j < mi - lo&&((k >= hi - mi)||B[j] <=C[k]))A1[i++] = B[j++];
    260         if (k < hi - mi && (j >= mi - lo || B[j] > C[k]))A1[i++] = C[k++];
    261     }*/
    262     //简化
    263     /*for (i = j = k = 0; j < mi - lo;)
    264     {
    265         if (k >= hi - mi || B[j] <= C[k])A1[i++] = B[j++];
    266         if (k < hi - mi && (j >= mi - lo || B[j] > C[k]))A1[i++] = C[k++];
    267     }*/
    268     free(B);
    269 }
    270 void MergeSort(int A[],int lo,int hi)
    271 {
    272     if (lo == hi - 1)
    273         return;
    274     int mi = (lo + hi) >> 1;
    275     MergeSort(A,lo, mi);
    276     MergeSort(A, mi, hi);
    277     Merge(A,lo, mi, hi);
    278 }
    279 //非递归算法
    280 void Merge_pass(int A[],int N, int length) //length为当前有序子列的长度
    281 {
    282     int i;
    283     for (i = 0; i <= N - 2 * length;i += 2 * length)
    284         Merge(A,i, i + length, i + 2 * length);
    285     if (i+length< N)    //如果最后有两个子列
    286         Merge(A, i, i+length, N);  
    287 }
    288 void Merge_Sort(int A[], int N)
    289 {
    290     int length = 1;
    291     while (length<=N)
    292     {
    293         Merge_pass(A, N, length);
    294         length *= 2;
    295     }
    296 }
    297 
    298 int main() 
    299 {
    300     int A[10];
    301     for (int i = 0; i < 10; i++)
    302         scanf("%d", &A[i]);
    303     //Bubble_Sort(A, 10);    //冒泡排序
    304     //Insert_Sort(A, 10);    //插入排序
    305     //Shell_Sort(A, 10);    //希尔排序
    306     //Selection_Sort(A, 10);    //选择排序
    307 
    308     //堆排序   //最小堆之憨憨算法
    309     /*for (int i = 1; i <= 10; i++)
    310         H->Elements[++H->Size] = A[i - 1];
    311     BuildMinHeap(H);   //构建最小堆
    312     Heap_Sort(A, 10);*/
    313 
    314     //堆排序  //最大堆之精比算法
    315     Heap_Sort(A, 10);
    316 
    317     //MergeSort(A,0,10) //归并排序递归算法
    318     //Merge_Sort(A,10);    //归并排序非递归算法
    319     Print(A, 10);
    320     return 0;
    321 }
    View Code

    快速排序:是排序算法中最快的 但要注意实现的细节(对于大规模数据来说)

    首先要注意主元的选取 对主元的选取会影响到算法的时间复杂度  还有就是快速排序是利用递归实现的 对于小规模数据 可能整体时间不入插入排序快 因此可以使用一个$Cutoff$ 当数据规模过小时 不使用快排 而使用 插入排序

     下面会给出对快速排序的测试

     表排序 

    不移动元素本身 而移动指针的 排序 叫做间接排序

    利用一个Table数组来对下标进行排序

    物理排序 

      N个数字的排列由若干个独立的环组成

    桶排序

    基数排序 

      用“次位优先" (Least Significant Digit)

      "主位优先"(Most Significant Digit)

    对排序的测试

     冒泡排序: 可以看出当数据量过大时 运行超时

    插入排序:虽然所有数据都能排序,但当数据量过大时,耗时增加

    希尔排序(Sedgewick):希尔排序快了不少

    选择排序:答案正确,耗时却不少

     堆排序(憨憨版本):速度也很快

     堆排序(精明版本): 速度也挺好

    归并排序(递归):也很快 但占的内存却很大 比前面的排序大了4、5倍 经检查 是因为没有在归并算法里free掉申请的空间

     每次申请完空间后释放掉 内存占用就少了许多

     归并排序(非递归) :看起来内存占用并没有少 一方面是因为我没有用陈越姥姥的方法去写递归与非递归的排序 更重要的是开辟的数组空间很大  但也可以看出 非递归算法比递归快一些

    对快速排序的测试:

    对pivot进行测试(此时不使用Cutoff来限定范围):

    ①pivot采取A[0]  有三个数据点耗时较多

     ②pivot采取A[mi]  速度不错

     ③pivot采取 三元选中值  某个数据点慢了些  其他都挺快的

     ④采用随机函数rand() 速度也行 不知道改一改获取rand值的函数会不会更快点

     对Cutoff进行测试(此时选取pivot为A[mi]):

    ①Cutoff取值为50

    ②Cutoff取100

     ③Cutoff取200

     ④Cutoff取300

     ⑤Cutoff取400

    PTA第27题 简单的一道桶排序题

     1 #define _CRT_SECURE_NO_WARNINGS  
     2 #include<stdio.h>
     3 #include<malloc.h>
     4 #include<stdlib.h>
     5 int Bucket[55];
     6 int main()
     7 {
     8     int N,Num;
     9     scanf("%d", &N);
    10     for (int i = 0; i < N; i++)
    11     {
    12         scanf("%d", &Num);
    13         Bucket[Num]++;
    14     }
    15     int count = 0;
    16     for (int i = 0; i < 55; i++)
    17     {
    18         if (Bucket[i])
    19         {
    20             printf("%d:%d
    ", i, Bucket[i]);
    21             count++;
    22         }
    23     }
    24 }
    View Code

     PTA 第25题 根据给的2串数组 判断是 插入排序还是 归并排序

    我是用归并的想法 不断检查以Length为长度的数组 判断是否满足是归并的最小条件(Length=2时满足) 

    如果满足 就继续向下查 更新之后需要的长度L 不是就返回去做下一步操作

    (os:这是PTA 2014年冬季考试题...我做了有一个小时四十分钟。。这还不算昨天思考的时间。。这要去考试不得凉凉)

      1 #define _CRT_SECURE_NO_WARNINGS  
      2 #include<stdio.h>
      3 #include<malloc.h>
      4 #include<stdlib.h>
      5 int A[110];
      6 int B[110];
      7 int L;
      8 void Print(int N)
      9 {
     10     int i;
     11     for (i = 0; i < N - 1; i++)
     12         printf("%d ", B[i]);
     13     printf("%d", B[i]);
     14 }
     15 int IsOrder(int B[],int lo, int hi)
     16 {
     17     for (int i = lo; i < hi - 1; i++)
     18         if (B[i] > B[i + 1])
     19             return 0;
     20     return 1;
     21 }
     22 int ChargeLength(int B[], int N, int Length)  //检查以Length为长度的序列
     23 {
     24     int i;
     25     for (i = 0; i < N -Length; i +=Length)
     26         if (!IsOrder(B, i, i+Length))
     27             return 0;
     28     if (i< N)
     29         if (!IsOrder(B, i, N))
     30             return 0;
     31     L = Length;
     32     return 1;
     33 }
     34 int Charge(int B[], int N)
     35 {
     36     int Length = 2;
     37     while(Length <=N)
     38     {
     39         if (ChargeLength(B, N, Length))
     40             Length *= 2;
     41         else
     42             if (Length > 2)
     43                 return 1;
     44             else
     45                 return 0;
     46     }
     47 }
     48 
     49 void Insert_Once(int B[],int i,int N)
     50 {
     51     int j;
     52     int Temp = B[i];
     53     for (j = i; j > 0 && B[j - 1] >Temp; j--)
     54         B[j] = B[j - 1];
     55     B[j] = Temp;
     56 }
     57 
     58 void Merge(int lo, int mi, int hi)
     59 {
     60     int* B1 = (int*)malloc(sizeof(int) * (mi - lo));
     61     for (int i = 0; i < mi - lo; i++)B1[i] = B[lo + i];
     62     int i, j, k;
     63     i = lo;
     64     j = 0;
     65     k = mi;
     66     while (j < mi - lo)
     67     {
     68         if (k >= hi || B1[j] <= B[k])B[i++] = B1[j++];
     69         if (k<hi && B1[j]>B[k])B[i++] = B[k++];
     70     }
     71     free(B1);
     72 }
     73 void Merge_Once(int B[], int Length, int N)
     74 {
     75     int i;
     76     for (i = 0; i < N - 2 * Length; i += 2 * Length)
     77         Merge(i, i + Length, i + 2 * Length);
     78     if (i + Length < N)
     79         Merge(i, i + Length, N);
     80 }
     81 
     82 int main()
     83 {
     84     int N;
     85     int Flag = 0;
     86     int OrderPosition = 0;
     87     scanf("%d", &N);
     88     for (int i = 0; i < N; i++)
     89         scanf("%d", &A[i]);
     90     for (int i = 0; i < N; i++)
     91         scanf("%d", &B[i]);
     92     if (Flag=Charge(B, N))
     93         printf("Merge Sort
    ");
     94     else
     95         printf("Insertion Sort
    ");
     96     for (int i = 0; i < N - 1; i++)
     97         if (B[i] <=B[i + 1])     //这里必须是大于等于
     98             OrderPosition = i + 1;
     99         else
    100             break;
    101     if (Flag)
    102         Merge_Once(B, L, N);
    103     else
    104         Insert_Once(B, OrderPosition+1, N);
    105     Print(N);
    106     return 0;
    107 }
    View Code

     PTA 第26题 根据给的两串数组 判断是 插入排序还是 堆排序 

    观察数据可以发现是利用 精明算法来 实现堆排序

    判断是 堆排序还是 插入排序 我是直接看 前三个元素 

    这道题 给出的例子至少会经过一次排序 所以看前三个元素 就可以知道是什么排序了 简单来说 插入排序最早就把前两个元素排好序了 而 堆排序对前两个元素的排序是最后才排的

    至于接下来做一步操作 插入排序很简单  堆排序我是直接把排序好的结果 与 给的 数据 进行比较 来找出 那个位置点

      1 #define _CRT_SECURE_NO_WARNINGS  
      2 #include<stdio.h>
      3 #include<malloc.h>
      4 #include<stdlib.h>
      5 int A[110];
      6 int B[110];
      7 int L;
      8 void Swap(int *C,int i, int j)
      9 {
     10     int temp = C[i];
     11     C[i] = C[j];
     12     C[j] = temp;
     13 }
     14 
     15 void Print(int N)
     16 {
     17     int i;
     18     for (i = 0; i < N - 1; i++)
     19         printf("%d ", B[i]);
     20     printf("%d", B[i]);
     21 }
     22 
     23 int Charge(int N)
     24 {
     25     int i;
     26     if (B[0] > B[1] && B[0] > B[2])
     27         return 1;
     28     else
     29         return 0;
     30 }
     31 
     32 void Insert_Once(int i, int N)
     33 {
     34     int j;
     35     int Temp = B[i];
     36     for (j = i; j > 0 && B[j - 1] > Temp; j--)
     37         B[j] = B[j - 1];
     38     B[j] = Temp;
     39 }
     40 
     41 void PrecDown(int i,int N)
     42 {
     43     int Parent, Child;
     44     int Tmp = A[i];
     45     for (Parent = i; Parent * 2 + 1 <= N; Parent = Child)
     46     {
     47         Child = Parent * 2 + 1;
     48         if (Child != N && A[Child] < A[Child + 1])
     49             Child++;
     50         if (Tmp >= A[Child])break;
     51         else
     52             A[Parent] = A[Child];
     53     }
     54     A[Parent] = Tmp;
     55 }
     56 
     57 void BuildMaxHeap(int N)
     58 {
     59     for (int i = (N - 1) / 2; i >= 0; i--)
     60         PrecDown(i, N - 1);
     61 }
     62 
     63 void Heap_Sort(int N)
     64 {
     65     for (int i = N - 1; i >= 0; i--)
     66     {
     67         Swap(A, 0, i);
     68         PrecDown(0, i-1);
     69     }
     70 }
     71 
     72 int FindI(int N)
     73 {
     74     int i;
     75     for (i = N - 1; i >= 0 && A[i] == B[i]; i--);
     76     return i;
     77 }
     78 
     79 void PrecDown_Once(int i)
     80 {
     81     Swap(B,0, i);
     82     int Parent, Child;
     83     int tmp;
     84     tmp = B[0];
     85     for (Parent = 0; (Parent * 2) + 1 <= i-1; Parent = Child)
     86     {
     87         Child = (Parent * 2) + 1;
     88         if (Child != i-1&& B[Child]<B[Child + 1])
     89             Child++;
     90         if (tmp >= B[Child])break;
     91         else
     92             B[Parent] = B[Child];
     93     }
     94     B[Parent] = tmp;
     95 }
     96 
     97 void Heap_Once(int N)
     98 {
     99     BuildMaxHeap(N);
    100     Heap_Sort(N);
    101     int i = FindI(N);
    102     PrecDown_Once(i);
    103 }
    104 
    105 int main()
    106 {
    107     int N;
    108     int Flag = 0;
    109     int OrderPosition = 0;
    110     scanf("%d", &N);
    111     for (int i = 0; i < N; i++)
    112         scanf("%d", &A[i]);
    113     for (int i = 0; i < N; i++)
    114         scanf("%d", &B[i]);
    115     if (Flag = Charge(N))
    116         printf("Heap Sort
    ");
    117     else
    118         printf("Insertion Sort
    ");
    119     for (int i = 0; i < N - 1; i++)
    120         if (B[i] <= B[i + 1])     //这里必须是大于等于
    121             OrderPosition = i + 1;
    122         else
    123             break;
    124     if (Flag)
    125         Heap_Once(N);
    126     else
    127         Insert_Once(OrderPosition + 1, N);
    128     Print(N);
    129     return 0;
    130 }
    View Code
  • 相关阅读:
    Beacon技术是什么?
    exclude kernel or other packages from getting updated
    (OK) running CORE & docker on Fedora 23 server
    (OK) dnf
    (OK) dnf
    rpm
    dnf
    dnf install -y kernel-4.2.3-300.fc23
    paper4—Multi-MPE_Trigger_Algorithm—testing
    paper4—Multi-MPE_Trigger_Algorithm
  • 原文地址:https://www.cnblogs.com/57one/p/11519108.html
Copyright © 2011-2022 走看看