算法分析之排序

一、插入排序(insertion sort)

1. 算法

每一步都将一条记录插入到已排序的有序表中,得到一个新的有序表,不断重复,直到全部插入排序完成。

void InsertionSort( ElenmentType A[], int N)
{
    int j, p;
    ElementType Tmp;
    for (P = 1; P<N; P++)
    {
        Tmp = A[P];
        for ( j = P; j>0&&A[j-1]>Tmp; j--)
        {
            A[j] = A[j-1];
        }
        A[j] = Tmp;
    }
}
1 def StraightInsertSort(array):
2     n = len(array)
3     for i in range(1, n):
4         tmp = array[i]
5         j = i
6         while j > 0 and array[j-1] > tmp:
7             array[j] = array[j-1]
8             j -= 1
9         array[j] = tmp

 

2.复杂度

最大时间复杂度:2+3+4+……+N = O(N2)

最小时间复杂度( 逆序数为O(N) ):O(N)

平均:O(N2)

空间复杂度:O(1); 稳定性:稳定

3.定理1:N个互异数组的平均逆序数是N(N-1)/4
定理2:通过交换相邻元素进行排序的任何算法平均需要Ω(N2)时间

 

二、希尔排序(Shellsort)(缩小增量排序Diminishing Increment Sort)

1.算法:基于插入排序改进

用选定步长将待记录分割为若干子序列分别进行直接插入排序,然后缩小步长,重复前面的步骤,知道全部排序完成。

void Shellsort( ElementType A[], int N )
{
    int i, j, Increment;
    ElementType Tmp;
    for (Increment = N/2; Increment > 0; Increment /= 2)
        for (i = Increment; i < N; i++)
        {
            Tmp = A[i];
            for (j = i; j>=Increment; j-=Increment)
                if (Tmp<A[j-Increment])
                    A[j] = A[j-Increment];
                else
                    break;
            A[j] = Tmp;
        }
}
 1 def ShellSort(array):
 2     n = len(array)
 3     increment = n//2
 4     while increment > 0:
 5         for i in range(increment, n):
 6             #tmp = array [i]
 7             j = i
 8             while j >= increment:
 9                 if array[j] < array[j-increment]:
10                     #array[j] = array[j-increment]
11                     tmp = array[j]
12                     array[j] = array[j-increment]
13                     array[j-increment] = tmp
14                 else:
15                     break
16                 j -= increment
17             #array[j] = tmp
18         increment = increment//2

 

2.复杂度

定理3:使用希尔增量排序的最坏情形运行时间为Θ(N2)

最好:O(N)

平均:O(NlogN)

空间复杂度:O(1); 稳定性:不稳定

 

三、堆排序(heapsort)

 1.算法:先通过下滤(percolate down)算法把原数组改为大根堆,然后用deleteMax算法循环地将最大值放入数组最后的位置上,即得到升序排序结果。

 1 #include <stdio.h>
 2 #define LeftChild(i) (2*i + 1)
 3 
 4 void PerDown(int a[], int i, int N)
 5 {
 6     int Child, Tmp;
 7     for(Tmp = a[i]; LeftChild(i) < N; i = Child)
 8     {
 9         Child = LeftChild(i);
10         if(Child != N-1 && a[Child + 1] > a[Child])
11             Child ++;
12         if(Tmp < a[Child])
13             a[i] = a[Child];
14         else
15             break;
16     }
17     a[i] = Tmp;
18 }
19 
20 void Heapsort(int a[], int N)
21 {
22     int i, tmp;
23     for(i = N/2; i >= 0; i--)  /* Build Max Heap */
24         PerDown(a, i, N);
25     for(i = N-1; i > 0; i--)  /* Delete Max */
26     {
27         tmp = a[0];
28         a[0] = a[i];
29         a[i] = tmp;
30         PerDown(a, 0, i);
31     }
32 }
33 
34 int main(int argc, char *argv[])
35 {
36     int i;
37     int a[] = {73, 64, 81, 29, 53, 36, 47, 91, 78,66};
38     Heapsort(a, 10);
39     for(i = 0; i < 10; i++)
40         printf("%d  ", a[i]);
41     return 0;
42 }
 1 def HeapSort(array):
 2     n = len(array)
 3     BuildHeap(array)
 4     for i in range(n-1, 0, -1):
 5         array[0], array[i] = array[i], array[0]
 6         PercolateDown(array, 0, i)
 7         
 8 def BuildHeap(array):
 9     n = len(array)
10     i = n//2-1
11     #for i in range(n//2, -1, -1)
12     while i >= 0:
13         PercolateDown(array, i, n)
14         i -= 1
15     
16 def PercolateDown(heap, i, n):  # Max Heap
17     tmp = heap[i]
18     while i <= n//2-1:
19         Lchild = 2*i + 1
20         
21         '''Rchild = Lchild + 1
22         if Lchild != n - 1 and heap[Lchild] < heap[Rchild]:
23             if tmp < heap[Rchild]:
24                 heap[i] = heap[Rchild]
25                 i = Rchild
26             else:
27                 break
28         else:
29             if tmp < heap[Lchild]:
30                 heap[i] = heap[Lchild]
31                 i = Lchild
32             else:
33                 break'''
34                 
35         if Lchild != n - 1 and heap[Lchild] < heap[Lchild+1]:
36             Lchild += 1
37         if tmp < heap[Lchild]:
38             heap[i] = heap[Lchild]
39             i = Lchild
40         else:
41             break
42     heap[i] = tmp

 

四、归并排序(mergesort)

1.算法:合并两个已排序的表;分治(divide-and-conquer);递归(recursion)
void MSort(ElementType A[], ElementType TmpArray[], int Left, int Right)
{
    int Center;
    if(Left < Right)
    {
        Center = (Left + Right)/2;
        MSort(A, TmpArray, Left, Center);
        MSort(A, TmpArray, Center+1, Right);
        Merge(A, TmpArray, Left, Center+1, Right);
    }
}
void Mergesort(ElementType A[], int N)
{
    ElementType *TmpArray;
    TmpArray = malloc(N*sizeof(ElementType));
    if(TmpArray != NULL)
    {
        MSort(A, TmpArray, 0, N-1);
        free(TmpArray);
    }
    else
        FatalError("No space for tmp array!")
}
/* Lpos = start of left half, Rpos = start of right half */
void Merge(ElementType A[], ElementType TmpArray[], 
    int Lpos, int Rpos, int RightEnd)
{
    int i, LeftEnd, NumElements, Tempos;
    LeftEnd = Rpos - 1;
    TmpPos = Lpos;
    NumElements = RightEnd - Lpos + 1;
    /*main loop*/
    while(Lpos <= LeftEnd && Rpos <= RightEnd)
        if(A[Lpos] <= A[Rpos])
            TmpArray[TmpPos++] = A[Lpos++];
        else
            TmpArray[TmpPos++] = A[Rpos++];
    while(Lpos <= LeftEnd)
        TmpArray[TmpPos++] = A[Lpos++];  //Copy rest of first half
    while(Rpos <= RightEnd)
        TmpArray[TmpPos++] = A[Rpos++];  //Copy rest of second half
    /* Copy TmpArray back */
    for (i = 0; i < NumElements; i++, RightEnd--)
        A[RightEnd] = TmpArray[RightEnd];
}

 

 1 def MergeSort(lists):
 2     if len(lists) <= 1:
 3         return lists
 4     num = len(lists)//2
 5     left = MergeSort(lists[:num])
 6     right = MergeSort(lists[num:])
 7     return Merge(left, right)
 8 
 9 def Merge(left, right):
10     l, r = 0, 0
11     result = []
12     while l < len(left) and r < len(right):
13         if left[l] < right[r]:
14             result.append(left[l])
15             l += 1
16         else:
17             result.append(right[r])
18             r += 1
19     result += left[l:]
20     result += right[r:]
21     return result

 

2.复杂度

最坏情形运行时间:O(NlogN)

【注:虽然归并排序的运行时间较优,但是它很难用于主存排序,主要问题在于合并两个排序的表需要线性附加内存,在整个算法中还要花费将数据拷贝到临时数组在拷贝回来这样一些附加工作,其结果严重放慢了排序的速度】

 

五、快速排序(quicksort)

1.算法:分割,递归

通过一趟排序将待排序记录分割成独立的两部分,其中一部分的所有记录都比另一部分的所有记录小,然后再按此方法对这两部分记录分别排序,知道所有排序完成。

三数中值分割法:使用左端、右端和中心位置上的三个元素的中值作为枢纽元。

#define Cutoff 3
void Quicksort( ElementType A[], int N)
{
    Qsort(A, 0, N-1);
}
/* Return median of Left, Center, and Right */
/* Order these and hide the pivot */
ElementType Median3( ElementType A[], int Left, int Right )
{
    int Center = (Left + Right)/2;
    if( A[Left] > A[Center] )
        Swap(&A[left], &A[Center]);
    if( A[Left] > A[Right] )
        Swap(&A[Left], &A[Right]);
    if( A[Center] > A[Right])
        Swap(&A[Center], A[Right]);
    /* Invariant: A[Left] <= A[Center] <= A[Right] */
    Swap( &A[Center], &A[Right-1] );
    return A[Right-1];
}
void Qsort( ElementType A[], int Left, int Right)
{
    int i, j;
    ElementType Pivot;
    if (Left + Cutoff <= Right)
    {
        Pivot = Median3( A, Left, Right );
        i = Left;
        j = Right-1;
        for(; ;)
        {
            while(A[++i] < Pivot){}
            while(A[--j] < Pivot){}
            if(i < j)
                Swap(&A[i], &A[j]);
            else
                break;
        }
        Swap(&A[i], &A[Right-1]);
        Qsort( A, Left, i-1);
        Qsort( A, i+1, Right);
    }
    else  // Do an insertion sort on the subarray
        InsertionSort( A+Left, Right-Left+1 );
}

 

 1 def QuickSort(array):
 2     n = len(array)
 3     QuickSortPartition(array, 0, n-1)
 4     
 5 def QuickSortPartition(array, left, right):
 6     Median(array, left, right)
 7     if left + 2 < right:
 8         pivot = array[right]
 9         i = left
10         j = right
11         while i < j:
12             while array[i] <= pivot and i < j:
13                 i += 1
14             while array[j] >= pivot and i < j:
15                 j -= 1
16             array[i], array[j] = array[j], array[i]
17             
18         array[right] = array[i]
19         array[i] = pivot
20         
21         QuickSortPartition(array, left, i-1 )
22         QuickSortPartition(array, i+1, right )
23             
24 def Median(array, left, right):
25     center = (left+right) // 2
26     if array[left] > array[center]:
27         array[left], array[center] = array[center], array[left]
28     if array[left] > array[right]:
29         array[left], array[right] = array[right], array[left]
30     if array[center] > array[right]:
31         array[center], array[right] = array[right], array[center]
32     if left + 2 < right:
33         array[center], array[right] = array[right], array[center]

 

2.复杂度

实践中最快的一直排序算法,平均运行时间为:O(NlogN)

最坏情形性能为:O(N2)

最好:O(NlogN)

空间复杂度:O(NlogN);稳定性:不稳定

对于很小的数组(N<=20),快速排序不如插入排序好。

 

 六、一般选择排序(SimpleSelectSort)

1.算法

从待排序记录中选出最小(大)的一条记录与第一个位置的记录交换,然后在剩下的记录中再找最小(大)的记录与第二个位置的记录交换,以此类推,直到全部完成。

 1 def SimpleSelectSort(array):
 2     n = len(array)
 3     for i in range(n-1):
 4         k = i
 5         for j in range(i+1, n):
 6             if array[j] < array[k]:
 7                 k = j
 8         tmp = array[i]
 9         array[i] = array[k]
10         array[k] = tmp

 

2.复杂度

最坏:O(N2);最好:O(N2);平均:O(N2)

空间复杂度:O(1); 稳定性:不稳定

 

七、冒泡排序(BubbleSort)

1.算法

在待排序记录中,自上而下的对相邻记录进行比较和调整,让较大的记录往下沉,较小的记录往上冒。

 1 def BubbleSort(array):
 2     n = len(array)
 3     for j in range(n-1):
 4         flag = False
 5         for i in range(n-1-j):
 6             if array[i] > array[i+1]:
 7                 #array[i], array[i+1] = array[i+1], array[i]
 8                 tmp = array[i]
 9                 array[i] = array[i+1]
10                 array[i+1] = tmp
11                 flag = True
12         if flag == False:
13             return

 

2.复杂度

最坏:O(N2);最好:O(N);平均:O(N2)

空间复杂度:O(1); 稳定性:稳定

 

转载于:https://www.cnblogs.com/tzhao/p/9381929.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值