一、插入排序
有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序。
1、直接插入排序
void InsertSort(int r[],int n)//0号单元用作暂存单元和监视哨
{
for (int i = 2; i <= n; i++)
{
r[0] = r[i];//暂存待插关键码
for (int j = i - 1; r[0] < r[j]; j--)//寻找插入位置
r[j + 1] = r[j];//后移
r[j + 1] = r[0];
}
}
2、希尔(Shell)排序
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插人排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
void ShellSort(int r[],int n)//0号单元用作暂存单元
{
for (int d = n / 2; d >= 1; d /= 2)
{
for (int i = d + 1; i <= n; i++)
{
r[0] = r[i];
for (int j = i - d; j > 0 && r[0] < r[j]; j -= d)
r[j + d] = r[j];
r[j + d] = r[0];
}
}
}
3、折半插入排序
采用折半查找的思想定位要插入的位置
void BinarySearchInsertSort(int r[],int n)
{
int middle = 0;
for(int i = 1; i < n; i++)
{
int low = 0,high = i - 1;
int temp = r[i];
while(low <= high)//折半查找合适的位置
{
middle = (low + high) / 2;
if(temp < r[middle])
high = middle - 1;
else
low = middle + 1;
}
for(int k = i ;k > middle; k--)
r[k]=r[k-1];
r[low] = temp;
}
}
二、交换排序
根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大(或较小)的记录向序列的尾部移动,键值较小(或较大)的记录向序列的前部移动。
1、冒泡排序
void BubbleSort(int r[],int n)
{
for(int i = 1; i < n; i++)
{
for(int j = 0; j < n - i; j++)
{
if(r[j] > r[j + 1])//比较交换相邻元素
{
int temp = r[j];
r[j] = r[j + 1];
r[j + 1] = temp;
}
}
}
}
2、鸡尾酒排序
也就是双向冒泡排序
void cocktailSort(int r[], int n)
{
int bottom = 0;
int top = n - 1;
bool swapped = true;
int temp,i;
while(swapped)
{
swapped = false;
for(i = bottom; i < top; i++)//从低到高
{
if(r[i] > r[i+1])
{
swapped = true;
temp = r[i];
r[i] = r[i + 1];
r[i + 1] = temp;
}
}
top--;
for(i = top; i > bottom; i--)//从高到低
{
if(r[i] < r[i - 1])
{
swapped = true;
temp = r[i];
r[i] = r[i - 1];
r[i - 1] = temp;
}
}
bottom++;
}
}
3、快速排序
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
int Partition(int r[],int first,int end)
{
int i = first,j = end;//初始化
while (i < j)
{
while (i < j && r[i] <= r[j]) j--;//右侧扫描
if (i < j)
{
int temp = r[i];
r[i] = r[j];
r[j] = temp;
i++;
}
while (i < j && r[i] <= r[j]) i++;//左侧扫描
if (i < j)
{
int temp = r[i];
r[i] = r[j];
r[j] = temp;
j--;
}
}
return i;//i为记录的最终位置
}
void QuickSort(int r[],int first,int end)
{
if (first < end)
{
int pivot = Partition(r,first,end);//一次划分
QuickSort(r,first,pivot - 1);//递归对左侧处理
QuickSort(r,pivot + 1,end);//递归对右侧处理
}
}
三、选择排序
每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法
1、简单选择排序
void SelectSort(int r[],int n)
{
for (int i = 1; i < n; i++)
{
int index = i;
for (int j = i + 1; j <= n; j++)
if (r[j] < r[index])
index = j;
if (index != i)
{
int temp = r[i];
r[i] = r[index];
r[index] = temp;
}
}
}
2、堆排序
堆排序(HeapSort)是一树形选择排序。堆排序的特点是:在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(或最小)的记录。
void sift(int r[],int k,int m)//0号单元用作交换操作的暂存单元
{
int i = k,j = 2 * i;//i指向被筛选结点,j指向结点i的左孩子
while (j <= m)//筛选还没有进行到叶子
{
if (j < m && r[j] < r[j + 1]) j++;//比较i的左右孩子,j指向较大者
if (r[i] > r[j])//根结点已经大于左右孩子中的较大者
break;
else
{
int temp = r[i];
r[i] = r[j];
r[j] = temp;
i = j;//被筛选结点位于原来结点j的位置
j = 2 * i;
}
}
}
void HeapSort(int r[],int n)//0号单元用作交换操作的暂存单元
{
int i;
for (i = n / 2; i >= 1; i--)//初始建堆,从最后一个分支结点至根结点
sift(r,i,n);
for (i = 1; i < n; i++)//重复执行移走堆顶及重建堆的操作
{
int temp = r[1];
r[1] = r[n - i + 1];
sift(r,1,n - i);
}
}
四、归并排序
void Merge(int r[],int r1[],int s,int m,int t)
{
int i = s,j = m + 1,k = s;
while (i <= m && j <= t)
{
if (r[i] <= r[j])//取r[i]和r[j]中的较小者放入r1[k]
r1[k++] = r[i++];
else
r1[k++] = r[j++];
}
if (i <= m)//若第一个子序列没处理完,则进行收尾处理
while (i <= m)
r1[k++] = r[i++];
else//若第二个子序列没处理完,则进行收尾处理
while (j <= t)
r1[k++] = r[j++];
}
void MergePass(int r[],int r1[],int n,int h)//从下标1开始存放待排序序列
{
int i = 1;
while (i <= n - 2 * h + 1)//待归并记录至少有两个长度为h的子序列
{
Merge(r,r1,i,i + h - 1,i + 2 * h - 1);
i += 2 * h;
}
if (i < n - h + 1)//待归并序列中有一个长度小于h
Merge(r,r1,i,i + h - 1,n);
else//待归并序列中只剩一个子序列
for (int k = i; k <= n; k++)
r1[k] = r[k];
}
//非递归法
void MergeSort1(int r[],int r1[],int n)//从下标1开始存放待排序序列
{
int h = 1;//初始时子序列长度为1
while (h < n)
{
MergePass(r,r1,n,h);//待排序序列从数组r中传到r1中
h = 2 * h;
MergePass(r1,r,n,h);//待排序序列从数组r1中传到r中
h = 2 * h;
}
}
//递归法
void MergeSort2(int r[],int r1[],int s,int t)
{
if (s == t)//待排序序列只有1个记录,递归结束
r1[s] = r[s];
else
{
int m = (s + t) / 2;
MergeSort2(r,r1,s,m);//归并排序前半个子序列
MergeSort2(r,r1,m + 1,t);//归并排序后半个子序列
Merge(r1,r,s,m,t);//将两个已排序的子序列归并
}
}
五、分配排序
1、桶式排序
桶式排序是一种简单的分配排序,其基本思想是:假定待排序记录的值都在0~m-1之间,设置m个桶,首先将值为i的记录分配到第i个桶中,然后再将各个桶中的记录依次收集起来。
struct Node //静态链表
{
int key;//记录的键值
int next;
};
struct QueueNode
{
int front;//队头指针
int rear;//队尾指针
};
void Distribute(Node r[],int n,QueueNode q[],int m,int first)
{//first为静态链表的头指针,从下标0开始存放待排序序列
int i = first;
while (r[i].next != -1)//依次分配每一个待排序记录
{
int k = r[i].key;
if (q[k].front == -1)//处理队列为空的情况
q[k].front = i;
else//在静态链表中实现插在队列尾部
r[q[k].rear].next = i;
q[k].rear = i;//修改队尾指针
i = r[i].next;//i后移,处理下一个记录
}
}
void Collect(Node r[],int n,QueueNode q[],int m,int first)
{//first为静态链表的头指针,从下标0开始存放待排序序列
int k = 0,last;
while (q[k].front != -1)//找到第一个非空队列
k++;
first = q[k].front;//first为第一个记录
last = q[k].rear;//last为队列k的最后一个记录
while (k < m)//处理每一个静态链队列
{
k++;
if (q[k].front != -1)//第k个队列非空
{
r[last].next = q[k].front;//将队列k的队头和前一个队列的队尾相接
last = q[k].rear;//last为当前收集后的最后一个记录
}
}
r[last].next = -1;//在静态链表中置尾标志
}
void BucketSort(Node r[],int n,int m,QueueNode q[])//从下标0开始存放待排序序列
{
int i,first;
for (i = 0; i < n; i++)//初始化链表
r[i].next = i + 1;
r[n - 1].next = -1;//设置尾标志和头指针
first = 0;
for (i = 0; i < m; i++)//初始化队列
q[i].front = q[i].rear = -1;
Distribute(r,n,q,m,first);//分配
Collect(r,n,q,m,first);//收集
}
2、基数排序
基数排序是借助对多关键码进行桶式排序的思想对单关键码进行排序。
struct Node
{
int key[d];//包括d个子关键码
int next;
};
struct QueueNode
{
int front;//队头指针
int rear;//队尾指针
};
void Distribute(Node r[],int n,QueueNode q[],int m,int first,int j)
{
int i = first;
while (r[i].next != -1)
{
int k = r[i].key[j];//取出记录i的第j个子关键码的值
if (q[k].front == -1)//处理队列为空的情况
q[k].front = i;
else//在静态链表中实现插在队列尾部
r[q[k].rear].next = i;
q[k].rear = i;//修改队尾指针
i = r[i].next;//i后移,处理下一个记录
}
}
void Collect(Node r[],int n,QueueNode q[],int m,int first)
{//first为静态链表的头指针,从下标0开始存放待排序序列
int k = 0,last;
while (q[k].front != -1)//找到第一个非空队列
k++;
first = q[k].front;//first为第一个记录
last = q[k].rear;//last为队列k的最后一个记录
while (k < m)//处理每一个静态链队列
{
k++;
if (q[k].front != -1)//第k个队列非空
{
r[last].next = q[k].front;//将队列k的队头和前一个队列的队尾相接
last = q[k].rear;//last为当前收集后的最后一个记录
}
}
r[last].next = -1;//在静态链表中置尾标志
}
void RadixSort(Node r[],int n,int m,QueueNode q[],int d)
{//从下标0开始存放待排序记录,d为记录中含有子关键码的个数
int i,first;
for (i = 0; i < n; i++)//初始化
r[i].next = i + 1;
r[n - 1].next = -1;
first = 0;
for (i = 0; i < m; i++)//初始化队列
q[i].front = q[i].rear = -1;
for (int j = 0; j < d; j++)
{
Distribute(r,n,q,m,first,j);//进行第j趟分配
Collect(r,n,q,m,first);//进行第j趟手机,first为头指针
}
}