线性表
交集
// 求递增有序顺序表A和B的交集,结果存入C(仍递增有序)
void Intersection(SqList A, SqList B, SqList &C) {
int i = 0, j = 0, k = 0; // i遍历A,j遍历B,k指向C的当前位置
// 双指针同步遍历,找共同元素
while (i < A.length && j < B.length) {
if (A.data[i] == B.data[j]) {
// 元素相等,加入结果,同时移动两个指针
C.data[k++] = A.data[i];
i++;
j++;
} else if (A.data[i] < B.data[j]) {
// A的当前元素更小,移动A的指针
i++;
} else {
// B的当前元素更小,移动B的指针
j++;
}
}
C.length = k; // 设置结果表长度
}
并集
// 求递增有序顺序表A和B的并集,结果存入C(仍递增有序)
void Union(SqList A, SqList B, SqList &C) {
int i = 0, j = 0, k = 0; // i遍历A,j遍历B,k指向C的当前位置
// 双指针同步遍历,按值大小加入结果
while (i < A.length && j < B.length) {
if (A.data[i] < B.data[j]) {
// A的当前元素更小,加入结果并移动A的指针
C.data[k++] = A.data[i++];
} else if (A.data[i] > B.data[j]) {
// B的当前元素更小,加入结果并移动B的指针
C.data[k++] = B.data[j++];
} else {
// 元素相等,加入结果并同时移动两个指针(去重)
C.data[k++] = A.data[i];
i++;
j++;
}
}
// 处理A的剩余元素
while (i < A.length) {
C.data[k++] = A.data[i++];
}
// 处理B的剩余元素
while (j < B.length) {
C.data[k++] = B.data[j++];
}
C.length = k; // 设置结果表长度
}
两张表合并
// 合并递增顺序表La、Lb为递减顺序表Lc
void mergeSqList(SqList La, SqList Lb, SqList &Lc) {
int i = La.length - 1; // La的“末尾元素”下标(从后往前遍历)
int j = Lb.length - 1; // Lb的“末尾元素”下标(从后往前遍历)
int k = 0; // Lc的“当前填充位置”下标(从前往后填充)
// 确保结果表Lc的长度足够
Lc.length = La.length + Lb.length;
// 双指针“从后往前”遍历,选大的元素放到Lc前端
while (i >= 0 && j >= 0) {
if (La.data[i] >= Lb.data[j]) {
Lc.data[k++] = La.data[i--];
} else {
Lc.data[k++] = Lb.data[j--];
}
}
// 处理La的剩余元素(若有)
while (i >= 0) {
Lc.data[k++] = La.data[i--];
}
// 处理Lb的剩余元素(若有)
while (j >= 0) {
Lc.data[k++] = Lb.data[j--];
}
}
就地逆置
// 顺序表就地逆置:时间O(n),空间O(1)
void reverseSqList(SqList &L) {
int i = 0, j = L.length - 1; // 双指针,i头、j尾
while (i < j) {
// 交换data[i]和data[j]
int temp = L.data[i];
L.data[i] = L.data[j];
L.data[j] = temp;
i++; // 头指针后移
j--; // 尾指针前移
}
}
判断是否有序
// 判断顺序表是否为“递增有序”
bool isSortedSqList(SqList L) {
// 空表或仅1个元素,视为有序
if (L.length <= 1) {
return true;
}
// 遍历相邻元素,检查是否“前 > 后”
for (int i = 0; i < L.length - 1; i++) {
if (L.data[i] > L.data[i + 1]) {
return false; // 存在逆序对,无序
}
}
return true; // 所有相邻元素满足“前 ≤ 后”,有序
}
删除重复元素
// 有序顺序表(递增/递减)删除重复元素(保留一个)
void deleteDuplicateSqSorted(SqList &L) {
if (L.length <= 1) return; // 空表或单元素表无需去重
int i = 0; // 有效元素的最后一个下标
for (int j = 1; j < L.length; j++) {
// 找到与当前有效元素不同的值,更新有效位置
if (L.data[j] != L.data[i]) {
i++;
L.data[i] = L.data[j]; // 覆盖重复元素
}
}
L.length = i + 1; // 更新有效长度
}
// 无序顺序表删除重复元素(保留一个)
void deleteDuplicateSqUnsorted(SqList &L) {
if (L.length <= 1) return;
int i = 0;
while (i < L.length) {
int j = i + 1;
// 检查后续元素是否与L.data[i]重复
while (j < L.length) {
if (L.data[j] == L.data[i]) {
// 重复元素:后续元素前移覆盖
for (int k = j; k < L.length - 1; k++) {
L.data[k] = L.data[k + 1];
}
L.length--; // 长度减1
} else {
j++; // 不重复则继续检查下一个
}
}
i++;
}
}
单链表
交集
// 求递增有序单链表A和B的交集,结果存入C(带头节点,仍递增有序)
void IntersectionList(LinkList A, LinkList B, LinkList &C) {
// 初始化结果链表C的头节点
C = (LinkList)malloc(sizeof(LNode));
C->next = NULL;
LNode *pa = A->next; // pa遍历A的有效节点
LNode *pb = B->next; // pb遍历B的有效节点
LNode *pc = C; // pc指向C的尾节点
// 双指针同步遍历,找共同元素
while (pa != NULL && pb != NULL) {
if (pa->data == pb->data) {
// 元素相等,创建新节点加入C的尾部
LNode *newNode = (LNode *)malloc(sizeof(LNode));
newNode->data = pa->data;
newNode->next = NULL;
pc->next = newNode;
pc = newNode;
// 同时移动两个指针
pa = pa->next;
pb = pb->next;
} else if (pa->data < pb->data) {
// A的当前元素更小,移动A的指针
pa = pa->next;
} else {
// B的当前元素更小,移动B的指针
pb = pb->next;
}
}
}
并集
// 求递增有序单链表A和B的并集,结果存入C(带头节点,仍递增有序)
void UnionList(LinkList A, LinkList B, LinkList &C) {
// 初始化结果链表C的头节点
C = (LinkList)malloc(sizeof(LNode));
C->next = NULL;
LNode *pa = A->next; // pa遍历A的有效节点
LNode *pb = B->next; // pb遍历B的有效节点
LNode *pc = C; // pc指向C的尾节点
// 双指针同步遍历,按值大小加入结果
while (pa != NULL && pb != NULL) {
if (pa->data < pb->data) {
// A的当前元素更小,创建新节点加入C的尾部
LNode *newNode = (LNode *)malloc(sizeof(LNode));
newNode->data = pa->data;
newNode->next = NULL;
pc->next = newNode;
pc = newNode;
// 移动A的指针
pa = pa->next;
} else if (pa->data > pb->data) {
// B的当前元素更小,创建新节点加入C的尾部
LNode *newNode = (LNode *)malloc(sizeof(LNode));
newNode->data = pb->data;
newNode->next = NULL;
pc->next = newNode;
pc = newNode;
// 移动B的指针
pb = pb->next;
} else {
// 元素相等,创建新节点加入C的尾部(去重)
LNode *newNode = (LNode *)malloc(sizeof(LNode));
newNode->data = pa->data;
newNode->next = NULL;
pc->next = newNode;
pc = newNode;
// 同时移动两个指针
pa = pa->next;
pb = pb->next;
}
}
// 处理A的剩余元素
while (pa != NULL) {
LNode *newNode = (LNode *)malloc(sizeof(LNode));
newNode->data = pa->data;
newNode->next = NULL;
pc->next = newNode;
pc = newNode;
pa = pa->next;
}
// 处理B的剩余元素
while (pb != NULL) {
LNode *newNode = (LNode *)malloc(sizeof(LNode));
newNode->data = pb->data;
newNode->next = NULL;
pc->next = newNode;
pc = newNode;
pb = pb->next;
}
}
两张表合并
void merge(LinkList La, LinkList Lb, LinkList &Lc) {
//a,b递增,c递减
LNode *pa = La->next;
LNode *pb = Lb->next;
LNode *p; // 临时指针,暂存要头插的节点
// 2. 用La的头节点作为Lc的头节点,初始化Lc的next为空
Lc = La;
Lc->next = NULL;
// 3. 双指针遍历:选较小节点头插
while (pa != NULL && pb != NULL) {
if (pa->data <= pb->data) {
p = pa; // 选La的节点
pa = pa->next;
} else {
p = pb; // 选Lb的节点
pb = pb->next;
}
// 头插法:将p插入Lc头部
p->next = Lc->next;
Lc->next = p;
}
// 4. 处理La的剩余节点
while (pa != NULL) {
p = pa;
pa = pa->next;
p->next = Lc->next;
Lc->next = p;
}
// 5. 处理Lb的剩余节点
while (pb != NULL) {
p = pb;
pb = pb->next;
p->next = Lc->next;
Lc->next = p;
}
// 6. 释放Lb的头节点(原Lb的节点已被复用)
free(Lb);
}
就地逆置
// 单链表就地逆置(带头节点):时间O(n),空间O(1)
void reverseLinkList(LinkList &L) {
LNode *prev = NULL; // 前驱节点(逆置后,第一个节点的next为NULL)
LNode *curr = L->next; // 当前要反转的节点(从第一个数据节点开始)
LNode *next; // 后继节点(暂存curr的下一个节点,防止断链)
while (curr != NULL) {
next = curr->next; // 暂存下一个节点
curr->next = prev; // 反转指针:当前节点指向前驱
prev = curr; // 前驱后移,指向当前节点
curr = next; // 当前节点后移,处理下一个节点
}
L->next = prev; // 头节点指向逆置后的第一个节点(原最后一个节点)
}
删除重复元素
// 有序链表(递增/递减)删除重复元素(保留一个)
void deleteDuplicateListSorted(LinkList &L) {
if (L->next == NULL) return; // 空表无需去重
LNode *p = L->next; // 当前节点(保留的节点)
LNode *q = p->next; // 遍历检查的节点
LNode *temp; // 临时指针,用于释放内存
while (q != NULL) {
if (q->data == p->data) {
// 重复节点:删除q
temp = q;
p->next = q->next;
free(temp); // 考研必写:避免内存泄漏
q = p->next; // 继续检查下一个节点
} else {
// 不重复:双指针后移
p = q;
q = q->next;
}
}
}
// 无序链表删除重复元素(保留一个)
void deleteDuplicateListUnsorted(LinkList &L) {
if (L->next == NULL) return;
LNode *p = L->next; // 外层遍历节点
LNode *q, *prev, *temp;
while (p != NULL) {
prev = p; // 内层遍历的前驱节点
q = p->next; // 内层遍历节点
while (q != NULL) {
if (q->data == p->data) {
// 重复节点:删除q
temp = q;
prev->next = q->next;
free(temp);
q = prev->next; // 继续检查下一个
} else {
prev = q;
q = q->next;
}
}
p = p->next; // 外层节点后移
}
}
判断是否有序
// 判断单链表是否为“递增有序”(带头节点)
bool isSortedLinkList(LinkList L) {
// 空表或仅头节点(无数据节点),视为有序
if (L == NULL || L->next == NULL) {
return true;
}
LNode *p = L->next; // 指向第一个数据节点
// 遍历所有相邻数据节点
while (p->next != NULL) {
if (p->data > p->next->data) {
return false; // 存在逆序对,无序
}
p = p->next; // 后移指针,检查下一对
}
return true; // 所有相邻节点满足“前 ≤ 后”,有序
}
按值和按位置查找