线性表的一些操作

线性表

交集

// 求递增有序顺序表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; // 所有相邻节点满足“前 ≤ 后”,有序
}

按值和按位置查找

posted @ 2026-01-25 21:02  叶臧  阅读(6)  评论(0)    收藏  举报