各种排序算法简介及实现

#include <iostream.h>
#include <stdlib.h>
#include <stdio.h>

using namespace std;
//冒泡排序 O(n^2)---稳定
冒泡排序将被排序的记录数组R[1..n]垂直排列,每个记录R[i]看作是重量为ki的气泡。根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R;凡扫描到违反本原则的轻气泡,就使其向上"漂浮"。如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止。
void BubbleSort(int *arr, int len)
{
  bool changed = false;
  for(int i = len - 1; i > 0; i--)
  {
    changed = false;
    for(int j = 0; j < i; j++)
    {
      if(arr[j] > arr[j+1])
      {
        int tmp = arr[j+1];
        arr[j+1] = arr[j];
        arr[j] = tmp;
        changed = true;
      }
    }
  }
  for(int i = 0; i < len; i++)
    cout<<arr[i]<<" ";
  cout<<endl; 
}

//插入排序 O(n^2)---稳定
插入排序的基本思想是每步将一个待排序的记录按其排序码值的大小,插到前面已经排好的文件中的适当位置,直到全部插入完为止。
void InsertSort(int *arr, int len)
{
  for(int i = 1; i < len; i++)
  {
    int key = arr[i];
    int j = i - 1;
    while(j >= 0 && key < arr[j])
    {
      arr[j + 1] = arr[j];
      j--;
    }
    arr[j + 1] = key;
  }
  for(int i = 0; i < len; i++)
    cout<<arr[i]<<" ";
  cout<<endl; 
} 


//选择排序O(n^2)---不稳定
直接选择排序的过程是:首先在所有记录中选出序码最小的记录,把它与第1个记录交换,然后在其余的记录内选出排序码最小的记录,与第2个记录交换......依次类推,直到所有记录排完为止。
void SelectSort(int *arr, int len)
{
  for(int i = 0; i < len; i++)
  {
    int index = i;
    for(int j = i; j < len; j++)
    {
      if(arr[index] > arr[j])
        index = j;
    }
    if(index != i)
    {
      int tmp = arr[i];
      arr[i] = arr[index];
      arr[index] = tmp;
    }
  }
  for(int i = 0; i < len; i++)
    cout<<arr[i]<<" ";
  cout<<endl; 
} 

//快速排序 O(n*lgn)

快速排序采用了一种分治的策略,通常称其为分治法,其基本思想是:将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。
    快速排序的具体过程如下:
    第一步,在待排序的n个记录中任取一个记录,以该记录的排序码为准,将所有记录分成两组,第1组各记录的排序码都小于等于该排序码,第2组各记录的排序码都大于该排序码,并把该记录排在这两组中间。
    第二步,采用同样的方法,对左边的组和右边的组进行排序,直到所有记录都排到相应的位置为止。
int GetSplit(int *arr, int start, int end)
{
  int key = arr[start];
  int begin = start;
  int split = 0;
  while(start < end)
  {
    while(start < end && arr[start] <= key) start++; 
    while(start < end && arr[end] >= key) end--;
    if(start < end)
    {
      int tmp = arr[start];
      arr[start] = arr[end];
      arr[end] = tmp;
    }
  }
  if(arr[start] >= key)
  {
    split = start - 1;
  }
  else
  {
    split = start;
  }
  arr[begin] = arr[split]; 
  arr[split] = key;
 
  return split;
}
void sort(int *arr, int start, int end)
{
  if(start < end)
  {
    int split = GetSplit(arr, start, end);
    sort(arr, split + 1, end);
    sort(arr, start, split - 1);
  }
}
void QuickSort(int *arr, int len)
{
  sort(arr, 0, len - 1);
  for(int i = 0; i < len; i++)
  cout<<arr[i]<<" ";
  cout<<endl; 
} 

//希尔排序O(n^(3/2))---不稳定
希尔(Shell)排序的基本思想是:先取一个小于n的整数d1作为第一个增量把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取得第二个增量d2<d1重复上述的分组和排序,直至所取的增量di=1,即所有记录放在同一组中进行直接插入排序为止。该方法实质上是一种分组插入方法。
    一般取d1=n/2,di+1=di/2。如果结果为偶数,则加1,保证di为奇数。
void ShellSort(int *arr, int len)
{
  for(int dx = len / 2; dx > 0; dx /= 2)
  {
    for(int j = dx; j < len; j += dx)
    {
      int k = j - dx;
      int key = arr[j];
      while(k >= 0 && key < arr[k])
      {
        arr[k + dx] = arr[k];
        k -= dx;
      }
      arr[k + dx] = key;
    }
  } 
  for(int i = 0; i < len; i++)
    cout<<arr[i]<<" ";
  cout<<endl; 
}
//归并排序-小到达O(nlgn)
void merge(int *arr, int bgn, int end1, int end2)
{
    int tmp[end2 - bgn];
    int i = bgn, j = end1;
    int k = 0;
    while(i < end1  && j < end2)
    {
        if(arr[i] <= arr[j])
        {
            tmp[k] = arr[i];
            i++;
        }
        else
        {
            tmp[k] = arr[j];
            j++;
        }
        k++;
    }
    if(j < end2)
    {
        while(j < end2)
        {
            tmp[k] = arr[j];
            j++;
            k++;    
        }
    }
    else if(i < end1)
    {
        while(i < end1)
        {
            tmp[k] = arr[i];
            i++;
            k++;
        }
    }
    for(int i = 0; i < end2 - bgn; i++)
    {
        arr[bgn + i] = tmp[i];
    }
}
void MergeSort(int *arr, int len)
{
    int range = 1;
    while(range < len)
    {
        int bgn = 0;
        while(bgn + range < len)
        {
            if(bgn + range * 2 < len)
            {
                merge(arr, bgn, bgn + range, bgn + range * 2);
            }
            else
            {
                merge(arr, bgn, bgn + range, len);
                break;
            }
            bgn += range * 2;
        }
        if(bgn + range > len)
        {
            int mid = (len - bgn) / 2;
            merge(arr, bgn, bgn + mid, len);
        }
        range *= 2;
    }
    
    for(int i = 0; i < len; i++)
        cout<<arr[i]<<" ";
    cout<<endl; 
} 
//堆排序 O(n*lgn)---不稳定
堆排序是一种树形选择排序,是对直接选择排序的有效改进。n个关键字序列
K1,K2,...,Kn称为堆,当且仅当该序列满足(Ki<=K2i且Ki<=K2i+1)或(Ki>=K2i且Ki>=K2i+1),(1<=i<=n/2)。根结点(堆顶)的关键字是堆里所有结点关键字中最小者,称为小根堆;根结点的关键字是堆里所有结点关键字中最大者,称为大根堆。
void heap(int *arr, int n)
{
  int k = (n - 1) / 2;
  while(k >= 0)
  {
    int j = 2 * k + 1;
    if(j + 1 <= n && arr[j] < arr[j + 1])
      j++;
    if(arr[k] < arr[j])
    {
      int tmp = arr[j];
      arr[j] = arr[k];
      arr[k] = tmp;
    }
    k--;
  }
  int max = arr[0];
  arr[0] = arr[n];
  arr[n] = max;
}
void HeapSort(int *arr, int len)
{
  for(int i = len - 1; i > 0; i--)
    heap(arr, i);
  for(int i = 0; i < len; i++)
    cout<<arr[i]<<" ";
  cout<<endl; 
}


int main(int argc, char *argv[])
{
  const int count = 9, length = count -1;
  int L[count] = {56, 49, 38, 65, 97, 76, 13, 27, 49};
  //BubbleSort(L, count);
  //InsertSort(L, count);
  //SelectSort(L, count);
  //QuickSort(L, count);
//MergeSort(L, count);
  //ShellSort(L, count);   HeapSort(L, count);   cout<<"Hello C-Free!"<<endl;   return 0; }
原文地址:https://www.cnblogs.com/geekma/p/2591851.html