基本排序算法的实现

1 交换排序

1.1 冒泡排序

从下往上(从后往前)比较,如果发现下面的比上面的小(轻),则交换二者的位置。利用哨兵(见注释部分),某趟没有任何交换则表明所有都排好序,退出。稳定排序,时间复杂度为0(n^2)

 

// 冒泡排序, 升序排列

void Swap(int& a, int& b)

{

       int t = a;

       a = b;

       b = t;

}

void BubbleSort(int arrary[], int len)

{

//     bool exchange;

       for (int i=0; i<len-1; i++) // 最多做n-1趟排序

       {

//            exchange = false;

              for (int j=len-1; j>i; j--)

              {

                     if (arrary[j] < arrary[j-1])

                     {

//                          exchange = true;

                            Swap(arrary[j], arrary[j-1]);

                     }

              }

 

//            if (!exchange)

//            {

//                   break;

//            }

       }

}

 

1.2 快速排序

它采用了一种分治的策略,通常称其为分治法。分治法的基本思想是:将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。

在数组中选中一个记录作为基准,将数组分成左右两个子区间,使得左边的值小于等于基准,右边的值大于等于基准。递归调用快速排序对左右两个子区间进行排序。不稳定排序,时间复杂度0(n*log(n))

 

int Partition(int arr[], int low, int high)

{

int pivot = arr[low];

 

while (low < high)

{

           while (low < high && arr[high] >= pivot)

                    --high;

          

           if (low != high)

                    Swap(arr[low], arr[high]);

          

           while (low < high && arr[low] <= pivot)

                    ++low;

          

           if (low != high)

                    Swap(arr[low], arr[high]);

}

 

return low;

}

 

void QuickSort(int arr[], int low, int high)

{

if (low < high)

{

           int n = Partition(arr, low, high);

           QuickSort(arr, low, n);

           QuickSort(arr, n+1, high);

}

}

 

2 插入排序

2.1 直接插入排序

每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序中的适当位置,直到全部记录插入完成为止。稳定排序,时间复杂度0n^2)。

void InsertSort(int arr[], int len)

{

int j;

int tmp;

 

for (int i=1; i<len; i++)

{

           if (arr[i] < arr[i-1])

           {

                    tmp = arr[i];

                    j = i-1;

                    do

                    {

                             arr[j+1] = arr[j];

                             j --;

                    } while (j>=0 && arr[j]>tmp);

 

                    arr[j+1] = tmp;

           }

}

}

 

2.2 希尔排序

希尔排序是对插入排序的改进,它每次排序把序列的元素按照某个增量分成几个子序列,对这几个子序列进行插入排序,然后不断的缩小增量扩大每个子序列的元素数量,直到增量为1的时候子序列就和原先的待排列序列一样了,此时只需要做少量的比较和移动就可以完成对序列的排序了。不稳定排序,时间复杂度0(n^(1+m))。注:0<m<1

// 增量从数组长度的一半开始,每次减小一倍

void ShellSort(int arr[], int len)

{

int temp;

for (int d = len/2; d>0; d /= 2)

{

           for (int i=d; i<len; i++)

           {

                    temp = arr[i];

                    for (int j=i; j>=d; j-=d)

                    {

                             if (temp < arr[j-d])

                             {

                                       arr[j] = arr[j-d];

                             }

                             else

                             {

                                       break;

                             }

                    }

 

                    arr[j] = temp;

           }

}

}

 

3 选择排序

3.1 直接选择排序

每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子文件的最后,直到全部记录排序完毕。非稳定排序,时间复杂度为0(n^2)

void SelectSort(int arr[], int len)

{        

int k;

for (int i=0; i<len; i++)

{

           k = i;

           for (int j=i+1; j<len; j++)

           {

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

                    {

                             k = j;

                    }

           }

 

           if (k != i)

           {

                    Swap(arr[i], arr[k]);

           }

}

}

 

3.2 堆排序

n个关键字序列KlK2Kn称为堆(Heap),当且仅当该序列满足如下性质(简称为堆性质)Ki≤K2iki≤K2i+1   Ki≥K2iKi≥K2i+1(1≤i≤ n)。注若索引从0开始,则是:Ki≤K2i+1Ki≤K2i+2   Ki≥K2i+1Ki≥K2i+2(0≤i≤ n-1)。节点i的父节点为floor(i/2)floor((i-1)/2)

若将此序列所存储的向量R[1..n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。 (即如果按照线性存储该树,可得到一个不下降序列或不上升序列)。不稳定排序,时间复杂度0(nlogn)

// start表示数组从01开始

void MaxHeapify(int arr[], int start, int end, int i)

{

       int lChild = (start==0) ? (2*i+1) : (2*i);

       int rChild = (start==0) ? (2*i+2) : (2*i+1);

 

       int larger = i;

 

       if (lChild<=end && arr[lChild]>arr[i])

       {

              larger = lChild;

       }

 

       if (rChild<=end && arr[rChild]>arr[larger])

       {

              larger = rChild;

       }

 

       if (larger != i)

       {

              Swap(arr[larger], arr[i]);

              MaxHeapify(arr, start, end, larger);

       }

}

 

void BuildMaxHeap(int arr[], int start, int end)

{

       int i = (start==0) ? ((end-1)/2) : (end/2);

 

       for (; i>=start; i--)

       {

              MaxHeapify(arr, start, end, i);

       }

}

 

// 堆排序

void HeapSort(int arr[], int start, int end)

{

       // build heap

       BuildMaxHeap(arr, start, end);

 

       // 依次将第一个与最后一个交换,然后保持堆性质

       // 这样就得到了升序排列

       while(end>start)

       {

              Swap(arr[start], arr[end]);

              end--;

              MaxHeapify(arr, start, end, start);

       }

}

4 归并排序

把待排序序列分成相同大小的两个部分,依次对这两部分进行归并排序,完毕之后再按照顺序进行合并。稳定排序,时间复杂度0(nlogn)

void Merge(int arr[], int start, int mid, int end)

{

       int n1 = mid-start+1;

       int n2 = end-mid;

       int* arr1 = new int[n1+1];

       int* arr2 = new int[n2+1];

 

       // 设置最后一个值为int最大值

       arr1[n1] = 2147483647;

       arr2[n2] = 2147483647;

 

       int i,j,k;

       for (i=0; i<n1; i++)

       {

              arr1[i] = arr[start+i];

       }

 

       for (i=0; i<n2; i++)

       {

              arr2[i] = arr[mid+i+1];

       }

      

       for (k=start,i=0,j=0; k<=end; k++)

       {

              if (arr1[i] <= arr2[j])

              {

                     arr[k] = arr1[i++];

              }

              else

              {

                     arr[k] = arr2[j++];

              }

       }

 

       delete arr1;

       delete arr2;

}

void MergeSort(int arr[], int start, int end)

{

       if (start < end)

       {

              int mid = (start+end)/2;

              MergeSort(arr, start, mid);

              MergeSort(arr, mid+1, end);

              Merge(arr, start, mid, end);

       }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值