排序
冒泡排序
基本原理(相邻元素比较交换)
从头到尾遍历数组,比较两个相邻的的元素,若前一个大于后一个则交换
一轮遍历后,最大的元素会冒泡到数组的末尾
重复以上步骤至排序完成
特点
时间复杂度:O(n²)
稳定,相同元素的相对顺序不会改变
代码示例
void bubbleSort(ElemType arr[], int n) {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
// 交换
ElemType temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
选择排序
基本原理(查找最大/小再交换)
在未排序的部分中找到最小(或最大)元素,将它与未排序部分的第一个元素进行交换
每次将一个元素放到最终位置,直至排序完成
特点
时间复杂度:O(n²)
不稳定,可能改变相同元素的相对位置
代码示例
void selectionSort(ElemType arr[], int n) {
for (int i = 0; i < n - 1; i++) {
int minIndex = i; // 假设当前位置是最小值
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j; // 找到新的最小值索引
}
}
// 交换
if (minIndex != i) {
ElemType temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
}
运用示例(冒泡排序)
void SqList_Sort(SqList& L)
{
for (int i = 0;i < L.length - 1;i++)
{
for (int j = 0;j < L.length - 1 - i;j++)
{
if (L.elem[j] > L.elem[j + 1])
{
ElemType t = L.elem[j];
L.elem[j] = L.elem[j + 1];
L.elem[j + 1] = t;
}
}
}
}
代码解读:
(SqList& L),关于何时用&
当需要对表中内容进行改动时(如插入、删除),需要加&
不需要改动时(如查找、输出),则不需要加&
与数组的差别
与数组相比,对顺序表的排序只改动了传入参数,以及将n改为了L.length
按序插入(已排序)
代码内容:
Status SqList_Insert_In_Order(SqList& L, ElemType e)
{
int i;
if (L.length >= L.listsize) // 检查表是否满
return OVERFLOW;
// 找到插入位置
for (i = 1; i <= L.length && L.elem[i - 1] <= e; i++);
// i 此时指向第一个大于 e 的位置
for (int j = L.length - 1; j >= i - 1; j--)
L.elem[j + 1] = L.elem[j]; // 将元素向后移动
L.elem[i - 1] = e; // 插入新元素
L.length++; // 更新长度
return OK; // 成功
}
代码逻辑
判满
遍历寻找插入位置,用计数器储存
移动元素留出空位
插入
更新长度
逆置
Status SqList_Reverse(SqList& L)
{
int left = 0, right = L.length - 1;
while (left < right)
{
int t = L.elem[left];
L.elem[left] = L.elem[right];
L.elem[right] = t;
left++;
right--;
}
return OK;
}
代码逻辑
对首尾使用计数器循环交换逼近
代码解读
while (left < right)
对左右(首尾)计数器进行比较,并在相撞时停止交换(交换完成)
删除重复元素
Status SqList_DeleteSame(SqList& L)
{
for (int i = 0; i < L.length; i++)
{
for (int j = i + 1; j < L.length; )
{
// 如果发现重复元素
if (L.elem[j] == L.elem[i])
{
// 移动元素
for (int k = j; k < L.length - 1; k++)
{
L.elem[k] = L.elem[k + 1];
}
// 长度减1
L.length--;
}
else {
// 只有当没有重复时才能往后走
j++;
}
}
}
return OK;
}
代码逻辑
使用双层循环,外层推进,内层遍历删除
删除特定元素
Status SqList_Delete_X(SqList& L, ElemType X)
{
for (int i = 0;i < L.length;)
{
if (L.elem[i] == X)
{
// 移动元素
for (int k = i; k < L.length - 1; k++)
{
L.elem[k] = L.elem[k + 1];
}
// 长度减1
L.length--;
}
else
{
// 只有当没有重复时才能往后走
i++;
}
}
return OK;
}
合并线性表(有序)
Status SqList_merge(SqList& LA, SqList& LB, SqList& LC)
{
LC.listsize = LA.listsize + LB.listsize;
LC.elem = (ElemType*)malloc(LC.listsize * sizeof(ElemType));
if (!LC.elem)
{
return OVERFLOW;
}
LC.length = 0;
int i = 0, j = 0, k = 0; // i指向LC, j指向LA, k指向LB
while (j < LA.length && k < LB.length)
{
if (LA.elem[j] < LB.elem[k])
{
LC.elem[i++] = LA.elem[j++];
}
else
{
LC.elem[i++] = LB.elem[k++];
}
}
// 处理LA或LB剩余元素
while (j < LA.length)
{
LC.elem[i++] = LA.elem[j++];
}
while (k < LB.length)
{
LC.elem[i++] = LB.elem[k++];
}
LC.length = i; // 更新LC长度
return OK;
}
代码逻辑
根据两表长度决定新表大小
为新表分配内存
比较两表元素有序放入新表内
代码解读
while (j < LA.length && k < LB.length)
使用while循环遍历LA
和LB
,直到有一个线性表遍历结束。
while (j < LA.length)
{
LC.elem[i++] = LA.elem[j++];
}
while (k < LB.length)
{
LC.elem[i++] = LB.elem[k++];
}
二者其实是或的关系,即较长的表继续将剩余元素输入进去