需要用到的结构的定义
template<typename KeyType, typename InfoType>
struct RedType
{
KeyType key;
InfoType otherinfo;
};
enum Status { ERROR = 0, OK = 1 };
template<typename ElemType>
struct SqList
{
ElemType data[MAX_LIST_SIZE + 1];
int length;
};
template<typename KeyType, typename InfoType>
using HeapType = SqList<RedType<KeyType, InfoType>>;
template<typename KeysType, typename InfoType>
struct SLCell
{
KeysType keys[MAX_NUM_OF_KEY];
InfoType otheritems;
int next;
};
template<typename KeysType, typename InfoType>
struct SLList
{
SLCell<KeysType, InfoType>* r;
int keynum, recnum;
};
using ArrType = int[RADIX];
直接插入排序
将数据分为两个部分,前面是已排好序的部分,后面是未排好序的部分。开始时假设第一个元素是已排好序的,之后每一轮都将未排好序的部分的第一个元素,与已排好序的部分的每一个元素,从后往前依次比较,不符合要求的元素就向后移一个位置,直到找到正确的位置。
时间复杂度(平均):O(n^2)
时间复杂度(最坏):O(n^2)
空间复杂度:O(1)
稳定性:稳定
template<typename KeyType,typename InfoType>
void insertSort(SqList<RedType<KeyType, InfoType>>& L)//直接插入排序
{
for (int i = 2; i <= L.length; i++)
{
if (L.data[i].key < L.data[i - 1].key)
{
L.data[0] = L.data[i];//哨兵节点用来记录本轮数据
L.data[i] = L.data[i - 1];
int j;
for (j = i - 2; L.data[0].key < L.data[j].key; j--)
L.data[j + 1] = L.data[j];
L.data[j + 1] = L.data[0];
}
}
}
起泡排序(冒泡排序)
每一趟从头到尾依次将相邻的两个元素进行比较,并根据要求交换位置,每一趟排序都可以确定一个元素到最后一个位置,直到所有元素都确定完成。同时,如果某一趟没有发生交换,则可以认为已经排好序了,此时无需继续排序,所以可以设置一个标志位,用于标志本轮是否发生交换,若未发生交换则可以直接退出排序。
时间复杂度(平均):O(n^2)
时间复杂度(最坏):O(n^2)
空间复杂度:O(1)
稳定性:稳定
template<typename KeyType, typename InfoType>
void bubbleSort(SqList<RedType<KeyType, InfoType>>& L)//起泡排序
{
bool exchange = true;//标志本轮是否发生交换
for (int i = 0; i < L.length && exchange; i++)//没发生交换可以直接退出
{
exchange = false;//默认没交换
for (int j = 1; j < L.length - i; j++)
{
if (L.data[j].key > L.data[j + 1].key)
{
exchange = true;//发生交换
RedType<KeyType, InfoType> t;
t = L.data[j];
L.data[j] = L.data[j + 1];
L.data[j + 1] = t;
}
}
}
}
简单选择排序
将数据分为两个部分,前面是已排好序的部分,后面是未排好序的部分。从头开始,每一次遍历未排好序的部分的所有元素,选择其中最小的元素,将其放到已排好序的部分的最后。
时间复杂度(平均):O(n^2)
时间复杂度(最坏):O(n^2)
空间复杂度:O(1)
稳定性:稳定
template<typename KeyType, typename InfoType>
int selectMinKey(SqList<RedType<KeyType, InfoType>>& L, int i)//选择从i开始到最后的最小关键字
{
int min = i;
for (int j = i + 1; j <= L.length; j++)
if (L.data[j].key < L.data[min].key)
min = j;
return min;
}
template<typename KeyType, typename InfoType>
void selectSort(SqList<RedType<KeyType, InfoType>>& L)//简单选择排序
{
for (int i = 1; i < L.length; i++)//从头开始遍历
{
int min = selectMinKey(L, i);//寻找最小关键字
if (min != i)
{//交换i与最小关键字的元素
RedType<KeyType, InfoType> t;
t = L.data[min];
L.data[min] = L.data[i];
L.data[i] = t;
}
}
}
快速排序
先确定一个枢轴,将所有数据分为两个部分,左边的比枢轴小,右边的比枢轴大,然后再对左右两个部分同样进行快速排序,直到序列有序。首先选择第一个元素作为枢轴,然后从最后一个元素开始向前,依次将每一个元素与枢轴进行比较,如果比枢轴小,则将该元素覆盖第一个元素,再从第一个元素向后,依次将每一个元素与枢轴进行比较,如果比第一个元素大,则将该元素覆盖上一步确定的元素,然后再从被覆盖的元素开始向前进行搜索与覆盖。以此类推,每一次都将不符合要求的元素覆盖另一边的元素,然后从另一边被覆盖的元素继续向前或向后搜索,直到两边相遇,相遇的位置再由枢轴覆盖,至此完成了一趟快速排序,然后继续对枢轴左右两边分别同样进行快速排序。
时间复杂度(平均):O(n logn)
时间复杂度(最坏):O(n^2)
空间复杂度:O(logn)
稳定性:不稳定
template<typename KeyType, typename InfoType>
int partition(SqList<RedType<KeyType, InfoType>>& L, int i, int j)//调整元素关于枢轴的位置并返回枢轴坐标
{
L.data[0] = L.data[i];//哨兵节点记录枢轴数据
KeyType pivotKey = L.data[i].key;//取最左边为枢轴
while (i < j)//从左右向中间扫描
{
while (i < j && L.data[j].key >= pivotKey)//因为取最左边为枢轴,所以要从最右边开始
j--;
L.data[i] = L.data[j];
while (i < j && L.data[i].key <= pivotKey)
i++;
L.data[j] = L.data[i];
}
L.data[i] = L.data[0];//枢轴位置
return i;
}
template<typename KeyType, typename InfoType>
void QSort(SqList<RedType<KeyType, InfoType>>& L, int i, int j)//递归进行快速排序
{
if (i < j)
{
int pivotLoc = partition(L, i, j);//找到枢轴
QSort(L, i, pivotLoc - 1);//枢轴左边快速排序
QSort(L, pivotLoc + 1, j);//枢轴右边快速排序
}
}
template<typename KeyType, typename InfoType>
void quickSort(SqList<RedType<KeyType, InfoType>>& L)//快速排序
{
QSort(L, 1, L.length);
}
堆排序
首先要建堆,从有孩子的元素中的最后一个元素开始到第一个元素进行建堆(将该元素与自己的孩子进行比较,若不符合要求,则将自己与孩子交换,然后继续与孩子的孩子比较,直到确定该元素的位置)。建堆完成之后,将堆分成两部分,前面是未交换过的部分,后面是已交换过的部分,初始时,所有元素均视为未交换过。每次将第一个元素与未交换过的元素中的最后一个元素进行交换,再从第一个元素到剩下未交换过的元素中的最后一个进行建堆,直到只剩下第一个元素未交换。
时间复杂度(平均):O(n logn)
时间复杂度(最坏):O(n logn)
空间复杂度:O(1)
稳定性:不稳定
template<typename KeyType, typename InfoType>
void heapAdjust(HeapType<KeyType, InfoType>& H, int s, int m)//调整堆
{//在s到m范围里调整s到合适的位置
RedType<KeyType, InfoType> R = H.data[s];
int j;
for (j = 2 * s; j <= m; j *= 2)//寻找s的后代,直到s比两个儿子都大
{
if (j < m && H.data[j].key < H.data[j + 1].key)//寻找s的左右儿子中大的那个,j必须小于m,否则j+1=m+1可能影响结果
j++;
if (H.data[j].key <= R.key)//必须用R,不能用s,因为s可能已经与j交换过,此时s其实是存的是交换的j的值
break;
H.data[s] = H.data[j];
s = j;
}
H.data[s] = R;
}
template<typename KeyType,typename InfoType>
void heapSort(HeapType<KeyType, InfoType>& H)//堆排序
{
for (int i = H.length / 2; i > 0; i--)//建堆
heapAdjust(H, i, H.length);
for (int i = H.length; i > 1; i--)//交换第一个和最后一个元素,然后重新调整堆
{
RedType<KeyType, InfoType>R = H.data[1];
H.data[1] = H.data[i];
H.data[i] = R;
heapAdjust(H, 1, i - 1);
}
}
基数排序
从低位到高位,对元素的关键字的每一位进行分配和收集。首先进行分配,根据位将每一个元素加入到对应位的静态链表中。然后进行收集,从小到大按每一个静态链表的顺序将元素链接起来。进行完一轮分配和收集之后继续对关键字的下一位进行分配和收集,直至每一位都分配收集完成。
时间复杂度(平均):O(d(n+rd))/O(dn)
时间复杂度(最坏):O(d(n+rd))/O(dn)
空间复杂度:O(rd)
稳定性:稳定
template<typename KeysType>
KeysType ord(KeysType K, int i)//计算第i位的值
{
KeysType t;
while (i--)
{
t = K;
t %= 10;
K /= 10;
}
return t;
}
template<typename KeysType, typename InfoType>
void distribute(SLCell<KeysType, InfoType>*& r, int i, ArrType& first, ArrType& end)
{
for (int j = 0; j < RADIX; j++)//初始化
first[j] = 0;
for (int p = r[0].next; p > 0; p = r[p].next)
{
int j = ord(r[p].keys[0], i);
if (first[j] == 0)//还没有元素
first[j] = p;//作为第一个元素
else//已经有元素
r[end[j]].next = p;//作为下一个元素
end[j] = p;//最后一个元素
}
}
template<typename KeysType, typename InfoType>
void collect(SLCell<KeysType, InfoType>*& r, int i, ArrType first, ArrType end)
{
int j;
for (j = 0; first[j] == 0; j++);//跳过无元素的部分
r[0].next = first[j];//设置第一个元素
int e = end[j];//最后一个元素的下标
while (j < RADIX - 1)
{
for (j++; j < RADIX - 1 && first[j] == 0; j++);//跳过无元素的部分
if (first[j] != 0)//因为找到有元素的部分而退出循环
{
r[e].next = first[j];
e = end[j];
}
}
r[e].next = 0;
}
template<typename KeysType, typename InfoType>
void radixSort(SLList<KeysType, InfoType>& L)//基数排序
{
ArrType first, end;
for (int i = 1; i <= L.keynum; i++)//对每一位进行分配和收集
{
distribute(L.r, i, first, end);
collect(L.r, i, first, end);
}
}
测试
int randint(int start, int end)
{
return rand() % (end - start) + start;
}
int main()
{
srand((unsigned int)time(0));
SqList<RedType<int, string>> L1, L2, L3, L4, L5;
initSqList(L1);
initSqList(L2);
initSqList(L3);
initSqList(L4);
initSqList(L5);
SLList<int, string> L6;
for (int i = 1; i < randint(10, 15); i++)
{
RedType<int, string> t;
t.key = randint(1, 1000);
insertSqList(L1, t, i);
insertSqList(L2, t, i);
insertSqList(L3, t, i);
insertSqList(L4, t, i);
insertSqList(L5, t, i);
}
int* data = new int[L1.length];
for (int i = 0; i < L1.length; i++)
data[i] = L1.data[i + 1].key;
initSLList(L6, data, L1.length, 3);
cout << "L1 = ";
for (int i = 1; i <= L1.length; i++)
cout << L1.data[i].key << " ";
cout << endl;
cout << "L2 = ";
for (int i = 1; i <= L2.length; i++)
cout << L2.data[i].key << " ";
cout << endl;
cout << "L3 = ";
for (int i = 1; i <= L3.length; i++)
cout << L3.data[i].key << " ";
cout << endl;
cout << "L4 = ";
for (int i = 1; i <= L4.length; i++)
cout << L4.data[i].key << " ";
cout << endl;
cout << "L5 = ";
for (int i = 1; i <= L5.length; i++)
cout << L5.data[i].key << " ";
cout << endl;
cout << "L6 = ";
for (int i = 1; i <= L6.recnum; i++)
cout << L6.r[i].keys[0] << " ";
cout << endl;
cout << "L1 after insertSort = ";
insertSort(L1);
for (int i = 1; i <= L1.length; i++)
cout << L1.data[i].key << " ";
cout << endl;
cout << "L2 after bubbleSort = ";
bubbleSort(L2);
for (int i = 1; i <= L2.length; i++)
cout << L2.data[i].key << " ";
cout << endl;
cout << "L3 after selectSort = ";
selectSort(L3);
for (int i = 1; i <= L3.length; i++)
cout << L3.data[i].key << " ";
cout << endl;
cout << "L4 after quickSort = ";
quickSort(L4);
for (int i = 1; i <= L4.length; i++)
cout << L4.data[i].key << " ";
cout << endl;
cout << "L5 after heapSort = ";
heapSort(L5);
for (int i = 1; i <= L5.length; i++)
cout << L5.data[i].key << " ";
cout << endl;
cout << "L6 after radixSort = ";
radixSort(L6);
for (int i = L6.r[0].next; i > 0; i = L6.r[i].next)
cout << L6.r[i].keys[0] << " ";
cout << endl;
system("pause");
return 0;
}