插入排序

稳定?不稳定: 稳定指的是两个相同的元素排序完成之后在表中相对位置不变。

直接插入

当插入第i个时,前i-1个已经排好了。

int tag = 0;
for(int i=1; i<n; i++)
{
if(a[i]<a[i-1])
{
tag = a[i];
int temp;
for(int k=i-1; k>=0; k--)
{
if(a[k]>tag)
{
a[k+1] = a[k];
temp = k;
}
else
{
break;
}
}
a[k+1] = tag;
}
}

默认第一个已经排好,从第二个开始从后往前排,如果第k个数比要比较的数大就把这个数往后排。

复杂度: n^2

折半插入

折半排序基于前面的直接插入,不同的是它通过二分找插入位置。然后再移动

int tag = 0;
for(int i=1; i<n; i++)
{
tag = a[i];
int low=0, high=i-1;
while(low<=high)
{
int mid = (low+high)/2;
if(a[mid]>tag)
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}//high+1是插入位置
for(int k=i-1; k>=high+1; k--)
{
a[k+1] = a[k];
}
a[high+1] = tag;
}

复杂度 n^2

希尔排序

思想: 把序列按gap划分成若干个子序列。例如有6个元素,gap是3,那么第0个和第3个是一个序列,第1个和第4个是一个序列。之后在每个子序列中直接插入。然后折半缩小gap。

第一个gap一般取n/2。

int gap = n/2;
int tag = 0;
while(gap != 0)
{
for(int i=gap; i<n; i++)//从gap开始是因为直接插入排序中默认第一个已经排序
{
tag = a[i];
int temp;
for(int k=i-gap; k>=0; k-=gap)
{
if(a[k]>tag)
{
a[k+tag] = a[k];
temp = k;
}
}
a[temp+tag] = tag;
}
gap /= 2;
}

复杂度:n(longn)^2。但这是一种不稳定的排序

起泡排序

起泡排序是过程是逐个比较,比较出最小的放到第一个,然后放到第二个。

int flag=0,exchange=0;
while(flag<n-1 && exchange==0)
{
exchange = 0;
for(int i=n-1; i>flag; i--)
{
if(a[i-1]>a[i])
{
a[i-1] = a[i] ^ a[i-1];
a[i] = a[i] ^ a[i-1];
a[i-1] = a[i] ^ a[i-1];
exchange = 1;
}
//这一步后小的在前面,然后下一次又是把i-1和i-2比,如果i-1小,又跑到前面
//这样第i-1个一直是最小的(相对于它后面的元素)
}
flag++;
}

复杂度 n^2

快速排序

以前的一篇

选择排序

直接选择排序

这个就不多说了。

int min = 2147483647;
int tag = 0;
for(int i=0; i<n-1; i++)
{
for(int k=i+1; k<n; k++)
{
if(a[k]<min)
{
min = a[k];
tag = k;
}
}
swap(a[i], a[tag]);
}

堆排序

堆排序是完全二叉树产生的数组。然后建立一个父节点比子节点大/小的数组。父节点比子节点大的叫大顶堆,父节点比子节点小的叫小顶堆。

假设父节点是i,那么两个子节点分别是i2和i2+1。下标要从1开始

过程,以小顶堆为例

  • 初始化,首先构造一个大顶堆,过程是用这个节点和它的父节点进行比较,如果小就交换位置,然后再和新位置的父节点进行比较。先拿第一个数和第二个数进行比较,如果第一个数比第二个数小那个交换位置。然后第三个数和第一个数比较。此外,还可以从小到大直接建

之后第4个数是插入到第二个数上的,就拿第四个数和第二个数比较,如果第四个数比第二个数小就把第二个数往上提,之后再和第一个数进行比较。然后依此类推。

  • 把第一个元素和最后一个元素进行交换,然后对前n-1个元素进行处理。开始我们建立的是大顶堆,现在我们把最大的放到后面就变成小顶堆了。并且这时不仅满足小顶堆,还满足左儿子一定比右儿子小。

  • 之后就是用根节点左右儿子中比较大的节点和根节点进行比较。然后如果比根节点大就进行换位。然后再在新位置和新的子节点进行比较。完成之后又把根节点放到最后。之后就重复第二步和第三步。(不画图了,难死我了)
//根据上面自己写的,拿过几个数据代过,如果想看更标准的可以看下面模板(饶命)
void Heap(int *a, int n)
{
for(int i=n/2; i>=1; i--)
{
int now = i;
while((now<<1) <= n)
{
int largest ;
int l = now << 1;
int r = (now<<1)+1;
if((now<<1)+1 == n)
{
if(a[l] > a[now])
{
int temp = a[l];
a[l] = a[now];
a[now] = temp;
}
break;
}
if(a[l] > a[r])
{
largest = l;
}
else
{
largest = r;
}
if(a[largest] > a[now])
{
int temp = a[largest];
a[largest] = a[now];
a[now] = temp;
now = largest;
}
else
{
break;
}
}
}//初始化

for(int i=n; i>1; i--)
{
a[1] = a[i] ^ a[1];
a[i] = a[i] ^ a[1];
a[1] = a[i] ^ a[1];
int now = 1;
while((now<<1) < i)
{
int big;
if((now<<1)+1 == i)
{
int temp = now<<1;
if(a[now] < a[temp])
{
a[now] = a[temp] ^ a[now];
a[temp] = a[temp] ^ a[now];
a[now] = a[temp] ^ a[now];
}
break;
}//只有左节点
if(a[now<<1] < a[(now<<1)+1])
{
big = (now<<1)+1;
}
else
{
big = now<<1;
}
if(a[big] > a[now])
{
a[big] = a[big] ^ a[now];
a[now] = a[big] ^ a[now];
a[big] = a[big] ^ a[now];
now = big;
}
else
{
break;
}
}
}
}

模板


#include <iostream>

//堆长度
int heapsize;

//大顶堆化
void MAX_HEAPIFY(int A[], int i)
{
int l = 2 * i; //把 i 的左儿子 下标 赋给l
int r = 2 * i + 1; //把 i 的左儿子 下标 赋给r
int largest; //3个里面最大的下标

if (l <= heapsize && A[l]>A[i])
largest = l;
else
largest = i;

if (r <= heapsize && A[r]>A[largest])
largest = r;

if (largest != i)
{
//交换 A[largest] 和 A[i]
int tmp = A[largest];
A[largest] = A[i];
A[i] = tmp;

MAX_HEAPIFY(A, largest);
}
}

//建堆
void BUILD_MAX_HEAP(int A[])
{
int i;
for (i = (int)(heapsize / 2); i >= 1; i--) {
MAX_HEAPIFY(A, i);
for (int j = 1; j <= 10; j++)
printf("%d ", A[j]);
printf("\n");
}
}

//堆排序
void HEAPSORT(int A[])
{
BUILD_MAX_HEAP(A); //ok

int i;
int tmp;
for (i = heapsize; i >= 2; i--) //A[1] 必定是最大的
{
//交换 A[1] 和 A[i]
tmp = A[1];
A[1] = A[i];
A[i] = tmp;

heapsize--;
MAX_HEAPIFY(A, 1);
}
}

int main()
{
int A[11] = { 0, 5, 3, 2, 1, 4, 6, 9, 7, 8, 10 };
//ok
int n = sizeof(A) / sizeof(int) - 1;
heapsize = n;

HEAPSORT(A);

for (int i = 1; i <= n; i++)
printf("%d ", A[i]);

return 0;
}

复杂度: nlogn.但是不稳定

归并排序

以前博客