一.直接插入排序
思想:把数组0下表作为哨兵位,之后的没考虑一位放入哨兵位的值与之前的值进行比较,大于则不进行操作;小于的话,依次向后移动(采用直接赋值的方法),直到找到插入的位置,替换值即可。
时间复杂度为O(n^2),属于简单排序。
方法一:
#include<iostream>
using namespace std;
/*直接插入排序*/
void InsertSort(int ar[],int n)
{
int j;
for (int i = 2; i < n; ++i)//从第三位开始遍历
{
if (ar[i] < ar[i- 1] )//如果小于前面一位则进行操作
{
ar[0] = ar[i];//将小于前面的值放入哨兵位
ar[i] = ar[i - 1];//再把前面一位覆盖到后面
for (j= i - 1; ar[0] < ar[j - 1]; --j)//寻找放入的位置
ar[j] = ar[j - 1];//数据整体后移,直到哨兵位大于ar[j-1]
ar[j] =ar[0] ;
}
}
for (int i = 1; i<n; i++)
cout << ar[i] << " ";
cout << endl;
}
int main()
{
int ar[] = { 0,13,4,34,56,23,16,72,64,79,14,25 };
int n = sizeof(ar) / sizeof(int);
InsertSort(ar, n);
return 0;
}
方法二:
//直接插入排序:将第一个数据看做一个顺序表,将后面的数据一次插入表中
void InsertSort(int a[], int n)
{
for(int i= 1; i<n; i++){
if(a[i] < a[i-1]){ //若第i个元素大于i-1元素,直接插入。小于的话,移动有序表后插入
int j= i-1; //表中最后一个数据
int x = a[i]; //复制为哨兵,即存储待排序元素
a[i] = a[i-1]; //先后移一个元素 (因为a[i]就是X,所以不怕丢失)
while(j>=0 && x < a[j]){ //查找在有序表的插入位置 (遍历表)
a[j+1] = a[j];
j--; //元素后移
}
a[j+1] = x; //插入到正确位置
}
}
}
int main()
{
int n;
cin>>n;
int *a=new int[n];
for(int j=0;j<n;j++)
cin>>a[j];
InsertSort(a,n);
for(int i=0;i<n;i++)
cout<<a[i];
delete []a;
}
2.堆排序
//堆排序:树形选择排序,将带排序记录看成完整的二叉树,第一步:建立初堆,第二步:调整堆
//第二步:调整堆
void HeapAdjust(int a[],int s,int n)
{
//调整为小根堆,从小到大
int rc=a[s];
for(int j=2*s;j<=n;j*=2)
{
if(j<n && a[j]>a[j+1])//判断左右子数大小
j++;
if(rc<=a[j])
break;
a[s]=a[j];
s=j;
}
a[s]=rc;
}
//第一步:建初堆
void CreatHeap(int a[],int n)
{
//小根堆
for(int i=n/2;i>0;i--)
HeapAdjust(a,i,n);
}
//整合
void HeapSort(int a[],int n)
{
CreatHeap(a,n);//第一步,建立初堆
for(int i=n;i>1;i--)
{
int x=a[1];//堆顶与最后一个元素互换
a[1]=a[i];
a[i]=x;
HeapAdjust(a,1,i-1);
}
}
int main()
{
int n;
cin>>n;
int *a=new int[n+1];
for(int j=1;j<n;j++)//注意:这里是从1开始的
cin>>a[j];
HeapSort(a,n);
for(int i=1;i<n;i++)
cout<<a[i];
delete []a;
}
3.选择排序
//简单选择排序:遍历一次找到最小与第一个元素呼唤位置,再从第二个元素开始遍历找到最小与第二个元素呼唤位置...
void SelectSort(int a[],int n)
{
for(int i=0;i<n-1;i++)
{
int k=i;//记录最小的那个下标的
for(int j=i+1;j<n;j++)
if(a[j]<a[k])
k=j;
if(k!=i)
{
int t=a[i];
a[i]=a[k];
a[k]=t;
}
}
}
int main()
{
int n;
cin>>n;
int *a=new int[n];
for(int j=0;j<n;j++)
cin>>a[j];
SelectSort(a,n);
for(int i=0;i<n;i++)
cout<<a[i];
delete []a;
}
4.快速排序
也叫分区排序,是目前应用最广泛的排序算法。实际上标准C++类库中的排序程序就被称为qsort,
排序算法是其实现中最基本的算法。
思想:任取待排序元素序列中的某个元素作为基准,按照该元素的排序码大小,将整个元素序列划分为
左右两个子序列:左侧子序列中所有元素的排序码都小于基准元素的排序码,右侧子序列中所有元素的排序
码都大于或等于基准元素的排序码,基准元素则排序在这两个子序列中间(这也是该元素最终应安放的位置)。
然后分别对这两个子序列重复施行上述方法,直到所有元素都排在相应位置上位置。
平均时间复杂度:O(nlog以2为底n)
int Partition(int Vector[], const int low, const int high)
{
int pivotpos = low,pivot = Vector[low];//定义出基准元素
for (int i = low + 1; i <= high; i++)//检测整个序列并进行划分
{
if (Vector[i] < pivot)
{
pivotpos++;
if (pivotpos != i)
swap(Vector[pivotpos], Vector[i]);//小于基准元素的交换到左侧去
}
}
Vector[low] = Vector[pivotpos];
Vector[pivotpos] = pivot;//将基准元素重新定位
return pivotpos;//返回基准元素
}
void QuickSort(int a[],const int left ,const int right) //采用递归实现
{
if (left < right)//当元素的序列大于1时候
{
int pivotpos = Partition(a, left, right);//进行划分
QuickSort(a, left, pivotpos - 1);//对左侧的子序列进行处理
QuickSort(a, pivotpos + 1, right);//对右侧的子序列进行处理
}//元素序列长度小于等于1时候不处理
}
改进算法:快速-直接插入混合排序算法
思想:虽然快速排序是一个效率很高的排序算法,但是对于长度很小的序列,快速
排序算法的速度并不比一些简单排序算法快,研究表明M取值5~25时候,采用直接插
入排序排序至少快10%。在快速排序算法的递归实现中程序多次因为小的子序列而调
用自身因此快速排序算法进行改进的一个简单方法:就是在递归调用过程,当待排序
的序列规模小于预先确定的M时候,程序调用直接插入排序算法对此子序列进行排序。
#define M 5
void QuickSort(int l[], const int left, const int right)
{
if (right - left <= M)return;
int pivotpos = Partition(l, left, right);
QuickSort(l, left, pivotpos - 1);
QuickSort(l, pivotpos + 1, right);
}
void InsertSort(int L[], const int left, const int right)
{
int temp, i, j;
for (i = left + 1; i < right; i++)
{
if (L[i] < L[i - 1])
{
temp = L[i];
j = i - 1;
do
{
L[j + 1] = L[j];
j--;
} while (j>left&&temp<L[j]);
L[j + 1] = temp;
}
}
}
void HybridSort(int L[], const int left, const int right)
{
QuickSort(L, left, right);
InsertSort(L, left, right);
}
5.冒泡排序
//传统冒泡排序
void maopao(int a[],int n)
{
for(int i=0;i<n-1;i++)
for(int j=0;j<n-i-1;j++)
if(a[j]>a[j+1])
{
int t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
int main()
{
int n;
cin>>n;
int *a=new int[n];
for(int j=0;j<n;j++)
cin>>a[j];
maopao(a,n);
for(int i=0;i<n;i++)
cout<<a[i];
delete []a;
}
6.希尔排序
思想:设待排序元素序列有n个元素,首先取一个整数gap<n作为间隔,将全部元素分为gap个子序列。然后缩小间隔gap,直到最后取gap==1,将所有元素放在同一个序列排序为止。
void Shellsort(int a[], const int left, const int right)
{
int i, j, gap = right - left + 1;//增量的初始化
int temp;
do {
gap = gap / 3 + 1;//求下一增量值
for (i = left / gap; i <= right; i++)//各子序列交替处理
{
if (a[i] < a[i - gap])//逆序
{
temp = a[i];
j = i - gap;
do {
a[j + gap] = a[j];//后移元素
j = j - gap;//再比较前一个元素
} while (j > left&&temp < a[j]);
a[j + gap] = temp;
}
}
}while(gap > 1);
}
void shell_sort(int array[], int length) {
int i;
int j;
int k;
int gap; //gap是分组的步长
int temp; //希尔排序是在直接插入排序的基础上实现的,所以仍然需要哨兵
for (gap = length / 2; gap>0; gap = gap / 2)
{
for (i = 0; i<gap; i++)
{
for (j = i + gap; j<length; j = j + gap)
{ //单独一次的插入排序
if (array[j] < array[j - gap])
{
temp = array[j]; //哨兵
k = j - gap;
while (k >= 0 && array[k]>temp)
{
array[k + gap] = array[k];
k = k - gap;
}
array[k + gap] = temp;
}
}
}
}
}
7.基数排序
也称多关键字排序 分发与回收
基数:关键值的大小 多关键字取决于基数的多少
比如:3位长的数先按照个位把整个数放在对应的下表链表中排序,然后依次回收到数组。 同理十位,百位依次进行,最终数组中的数就排好序了
#include<iostream>
using namespace std;
#include<list>
list<int> lst[10];
void Distribute(int ar[], int n, int k)
{
int tmp;
int x;
for (int i = 0; i < n; i++)
{
x = k;
tmp = ar[i];
while (tmp&&x > 0)
{
tmp /= 10;
x--;
}
lst[tmp % 10].push_back(ar[i]);
}
}
void Collect(int ar[])
{
int k = 0;
for (int i = 0; i < 10; i++)
{
while (!lst[i].empty())
{
ar[k++] = lst[i].front();
lst[i].pop_front();
}
}
}
void RadixSort(int ar[], int n)
{
for (int i = 0; i < 3; i++)
//循环三次第一次从个位放入链表,第二次从十位位,第三次从百位
{
Distribute(ar, n, i);
Collect(ar);
}
}
int main()
{
int ar[] = { 278, 109, 63, 930, 589, 184, 505, 269, 8, 83 };
int n = sizeof(ar) / sizeof(int);
RadixSort(ar, n);
for (int i = 0; i<n; ++i)
cout << ar[i] << " ";
cout << endl;
return 0;
}