1.直接插入排序,时间复杂度n^2
void InsertSort(int R[], int n)//对含n个元素的数组R排序
{
int i,j, temp;
for (int i = 1;i < n;i++)//初始时有序区只有R[0]一个元素
{
if (R[i] < R[i - 1])//从最靠近有序区那个元素开始找,找到比有序区最大元素
//也就是最右边元素更小的元素,然后插入有序区
{
temp = R[i];
j = i - 1;
while (j >= 0 && R[j] > temp)//有序元素全部右移,直到把temp插入停止
{
R[j + 1] = R[j];
j--;
}
R[j+1] = temp;
}
}
for (int i = 0;i < n;i++)
cout << R[i] << " ";
}
2.折半插入排序,时间复杂度为o(n^2)
折半查找的思想是先二分查找到temp应该插入到有序区的位置,然后再把该位置右边的有序区元素集体右移一位,此时temp的位置已经空了,再把temp插入
void BinInsertSort(int R[], int n)
{
int i, j, low, high, mid, temp;
for (int i = 0;i < n;i++)
{
if (R[i] < R[i - 1])//找到反序的可以插入有序区的R[i]
{
temp = R[i];//先把要插入的元素临时保存起来
low = 0, high = i - 1;//找到有序区的上下限,然后二分查找插入位置
while (low <= high)
{
mid = (low + high) / 2;
if (temp < R[mid])
high = mid - 1;
else
low = mid + 1;
}
//这里找到的最终位置为high+1,因为当low和high相邻时,此时temp即在low和high中间
//再进行二分,得到mid=low,然后会temp>=R[mid],所有会有low=mid+1,此时low和high重合
//再进行二分,会有mid=low=high,然后high=mid-1,此时跳出循环,high的位置往前
//移动了一步,它右边那个位置应该是temp插入的位置,也就是high+1;
for (int j = i - 1;j >= high + 1;j--)
R[j + 1] = R[j];//全体有序区插入位置右边元素右移一位
R[high + 1] = temp;
}
}
}
3.希尔排序(插入排序),就是先把元素分成d组,然后对d组元素进行直接插入排序,时间复杂度n^1.3,然后把d一直减小到1为止,每减小一次进行一次直接插入排序
void ShellSort(int R[], int n)
{
int i, j, k, temp;
int d = n / 2;
while (d > 0)//表示一直到d=1还可以进行各组的直接插入排序
{
for (i = d;i < n;i++)//传统希尔排序从1开始,这里从d开始,因为有d组,前面0到d-1一共
//d个元素分布代表d组序列的有序区初始元素,为一个,每隔d个元素对每组序列进行一次
//直接插入排序操作,所以循环从d到n是对所有序列进行的完整操作
{
temp = R[i];
j = i - d;
while (j >= 0 && R[j] > temp)//表示可以插入到该组元素前面的有序区里面
{
R[j + d] = R[j];
j = j - d;
}
R[j + d] = temp;
}
d = d / 2;
}
//这里进行了d从n/2,n/4,n/8一直到1的分组,对每种分组分别进行直接插入排序
//你也许会有疑问,当n=1时不就是直接对这个序列R[n]进行直接插入排序吗?为什么要加前面的操作
//事实上,前面这些操作让这个序列R[n]的混乱度不断降低,越到后面所需要进行的操作越少
//所以这里当进行到d=1然后直接插入排序时,所需要的操作和直接进行直接插入排序所需要的操作少得多
}
4.冒泡排序(交换排序),这里不多做赘述,十分简单,时间复杂度为n^2
void BubbleSort(int R[], int n)
{
int i, j;
for(i=0;i<n-1;i++)
for (j = n - 1;j > i;j--)
{
if (R[j] < R[j - 1])
swap(R[j], R[j - 1]);
}
}
5.快速排序(交换排序)时间复杂度为nlogn,先找到任意一个元素,一般是第一个元素,然后对该序列进行快速排序,把比temp小的元素放到左边把比temp大的元素放到右边,经过一轮交换,可以把temp放到它最终的位置上,然后再对左右进行排序
int partition(int R[], int start, int over)
{
int i = start, j = over, temp = R[start];
while (i < j)//到i=j时temp左边全为小于temp的元素,右边全为大于temp的元素
{
while (j > i&& R[j] >= temp)
j--;//从右边开始直到找到小于temp的元素,循环结束,把该元素R[j]放到temp原来的位置R[i]上面
R[i] = R[j];
while (j > i&& R[i] <= temp)
i++;//从左边开始直到找到比temp大的元素,循环结束,并把R[i]放入已经移走的R[j]位置上
R[j] = R[i];
}
R[i] = temp;//循环结束,得到temp的最终位置在i上,即temp已经归位,在最终的有序位置上面
return i;
}
void QuickSort(int R[], int start, int over)
{
int i;
if (start < over)
{
i = partition(R, start, over);//此时已经找到最终应该放入位置i的元素,位置i的元素已经归位
QuickSort(R, start, i - 1);//递归对左边进行快速排序
QuickSort(R, i + 1, over);
}
}
6.简单选择排序(选择排序)时间复杂度n^2
void SelectSort(int R[], int n)
{
int i, j, temp;
for (i = 0;i < n - 1;i++)
{
temp = i;//这里必须使用temp记录i,因为后面的操作会不停变换temp,但是i是不能被改变的
for (j = i + 1;j < n;j++)
if (R[j] < R[temp])
temp = j;//这个循环找到i后面最小的元素R[temp]
if (temp != i)//最小的元素不是R[i]本身,那么就交换
{
swap(R[i], R[temp]);
}
}
}
7.堆排序,这里因为要用堆处理,所有数据是从R[1]到R[n]的,而不是从R[0]开始,首先要采用堆的筛选算法,把堆变成一根最大堆,然后R[1]一定是堆里面最大的元素,此时无序区的最后一个元素为R[n],直接交换R[1]与R[n],然后对前面无序区n-1个元素继续筛选(此时R[n]已经在有序区),把其变成最大堆之后再进行交换,直到进行n-1次所有元素归位
void sift(int R[], int low, int high)
{
int i = low, j = 2 * i;
int temp = R[i];
while (j <= high)
{
if (j < high && R[j] < R[j + 1])
j++;//选取R[i]更大的那个孩子结点
if (temp < R[j])
{
R[i] = R[j];//把大于根节点的孩子结点上浮
i = j;//把根节点下浮继续进行交换
j = j * 2;
}
else
break;//表示已经是最大堆了,不需要进行调整了
}
R[i] = temp;//把初始的根节点放到最后的根节点位置i上面,此时i也可能是最下面的叶子结点
}
void HeapSort(int R[], int n)
{
int i;
for (i = n / 2;i >= 1;i--)
sift(R, i, n);//把初始堆变成最大堆
for (i = n;i >= 2;i--)//进行n-1次归位与调整,得到有序序列
{
swap(R[i], R[1]);//把最大值放入无无序区最后的位置,此时这个位置变成有序区
sift(R, 1, i - 1);//对交换后的无序区元素进行筛选
}
}
8.归并排序,merge进行两两归并,mergepass把n/length条序列分别两两归并,得到n/(2*length)条序列;mergesort进行log2底n次mergepass,最终把序列不断两两归并成一条有序序列
void Merge(int R[], int low, int mid, int high)//简单的把两段有序序列合并成一段有序序列
{
int* R1;
int i = low, j = mid + 1, k = 0;
R1 = new int[MaxSize];
while (i <= mid && j <= high)//先把元素放入R1直到有一个序列放完为止
{
if (R[i] <= R[j])
{
R1[k] = R[i];
i++;k++;
}
else
{
R1[k] = R[j];
j++;k++;
}
}
while (i <= mid)//表示第一段没有全部归并
{
R1[k] = R[i];
i++;k++;
}
while (j <= high)//表示第二段没有完全归并
{
R1[k]= R[j];
j++;k++;
}
for (k = 0, i = low;i <= high;k++, i++)
R[i]= R1[k];
delete []R1;
}
void MergePass(int R[], int length, int n)//把序列分成length长的若干段序列,然后分别两两归并
{
int i;
for (i = 0;i + 2 * length - 1 < n;i = i + 2 * length)
Merge(R, i, i + length - 1, i + 2 * length - 1);
if (i + length - 1 < n - 1)
Merge(R, i, i + length - 1, n - 1);//收尾,把最后可能留下的序列归并
}//这里一开始有n/length段序列,经过归并后变成了n/(2*length)段有序序列
void MergeSort(int R[], int n)
{
int length;
for (length = 1;length < n;length = 2 * length)
MergePass(R, length, n);//每一次执行,length变成原来的两倍,有序序列数量减半
//直到length变成n/2,进行最后一次归并,得到最终的有序序列
//这里进行log2底n次归并,每一次归并把n/length条有序序列变成n/(2*length)条
}
9.基数排序
假设数据为r进制,则设置r个链队,假设数据最大有d位,则进行d次分配收集这里是从最低位开始分配收集,直到把元素放入链队里面,然后再把链队从低到高连接起来组成新链这样进行d次分配收集之后,得到的链串里面的数据就是有序的
typedef struct node {
char data[MaxSize];
struct node* next;
}NodeType;
void RadisSort(NodeType*& p, int r, int d)//r代表基数,十进制则r=10,d为数据位数
{
NodeType* head[MaxSize], * tail[MaxSize], * t;
int i, j, k;
for (i = 0;i < d - 1;i++)//从低位到高位循环,一般情况下i=0是个位,
{
for (j = 0;j < r;j++)//初始化各链队指针,基数为r所以需要r个链队
head[j] = tail[j] = NULL;
while (p != NULL)//对原来链表中各个结点元素放入相应的链队中
{
k = p->data[i] - '0';//此时是对第i位进行操作,找到每个元素第i位的数值,存在k中
if (head[k] == NULL)
{
head[k] = p; // 并把链表对应的结点放入链队head[k]中
tail[k] = p;
}
else
{
tail[k]->next = p;tail[k] = p;
}
p = p->next;//取下一个结点元素,直到所有元素放入对应的链队,完成了收集过程
}
p = NULL;//重新用p来收集所有结点
for(j=0;j<r;j++)//一共有r条链队需要拼接在一起
if (head[j] != NULL)//这个链队有结点
{
if (p == NULL)
{
p = head[j];t = tail[j];//把该链队赋给p
}
else
{
t->next = head[j];t = tail[j];//把链队连接在p链上
}
}
t->next = NULL;
}
}