常见的链表操作

  1. 链表的操作主要体现在对指针的操作,考察对指针的理解。
  2. 对链表的操作关键在于对链表的遍历,一种是常规正序遍历,另一种是逆序时采用的递归遍历。
  3. 链表复杂操作可能会需要多个指针协调工作。
  4. 注意考虑链表为空的情况。
//链表定义
typedef struct LNode{
    int data;
    struct LNode *next;
}LNode,*LinkList;

typedef struct LNode_C{
    char data;
    struct LNode_C *next;
}LNode_C,*LinkList_C;

typedef struct LNode_Dul{
    int data;
    struct LNode_Dul *next;
    struct LNode_Dul *prior;
    int freq;
}LNode_Dul,*LinkList_Dul;

 

一、链表的创建

顺序生成一个有头结点单链表,元素类型为int
//顺序生成一个有头结点单链表,元素类型为int
void CreatList(LinkList *ptr_L)
{
    *ptr_L = new LNode();
    (*ptr_L)->next = NULL;
    LinkList p = *ptr_L;

    int data;
    while (cin>>data)
    {
        LinkList temp_L = new LNode();
        temp_L->next = NULL;
        temp_L->data = data;
        p->next = temp_L;
        p = temp_L;
    }
}
逆序生成一个有头结点单链表,元素类型为int
//逆序生成一个有头结点单链表,元素类型为int
void CreatList_L(LinkList &L,int n){
    L=(LinkList)malloc(sizeof(LNode));
    L->next=NULL;
    cout<<"请从后到前输入链表内容:"<<endl;
    for (int i=n;i>0;i--)
    {
        LinkList p=(LinkList)malloc(sizeof(LNode));
        cin>>p->data;
        p->next=L->next;
        L->next=p;
    }
}
逆序生成一个有头结点单循环链表,元素类型为int
//逆序生成一个有头结点单循环链表,元素类型为int
void CreatList_L_Cir(LinkList &L,int n){
    L=(LinkList)malloc(sizeof(LNode));
    L->next=L;//最后元素指向L
    cout<<"请从后到前输入链表内容:"<<endl;
    for (int i=n;i>0;i--)
    {
        LinkList p=(LinkList)malloc(sizeof(LNode));
        cin>>p->data;
        p->next=L->next;
        L->next=p;
    }
}
逆序生成一个有头结点双循环链表,元素类型为int
//逆序生成一个有头结点双循环链表,元素类型为int
void CreatList_L_Cir_Dul(LinkList_Dul &L,int n){
    L=(LinkList_Dul)malloc(sizeof(LNode_Dul));
    L->next=L;//最后元素指向L
    cout<<"请从后到前输入链表内容:"<<endl;
    for (int i=n;i>0;i--)
    {
        LinkList_Dul p=(LinkList_Dul)malloc(sizeof(LNode_Dul));
        if(i==n) L->prior=p;
        p->freq=0;
        cin>>p->data;

        p->prior=L;//前驱
        L->next->prior=p;//前驱

        p->next=L->next;//后继
        L->next=p;//后继,此处L->暂存p以供下次循环使用
    }
}
 二、单链表的操作
链表反转
//链表反转。先遍历,然后前方插入
void InverseList(LinkList *L)
{
    if ((*L) == NULL)
    {
        throw "error";
    }

    if ((*L)->next == NULL || (*L)->next->next ==NULL)
    {
        return;
    }

    LinkList pre = (*L)->next;
    LinkList p = (*L)->next->next;

    LinkList tmpFirst = (*L)->next;

    while(p)
    {
        LinkList tmp = p->next;

        (*L)->next = p;
        p->next = pre;

        pre = p;
        p = tmp;
    }
    tmpFirst->next = NULL; 
}
在带头结点的单链表结构上实现线性表操作,定位值为x的结点
//在带头结点的单链表结构上实现线性表操作,定位值为x的结点
int Locate(LinkList L,int x){
    int i=0;
    LinkList p=L;
    while(p&&p->data!=x){
        p=p->next;
        i++;
    }
    if (!p) return 0;
    return i;
}
在带头结点的单链表结构上实现线性表操作,求链表长度
//在带头结点的单链表结构上实现线性表操作,求链表长度
int ListLength_L(LinkList L){
    if (L == NULL)
    {
        throw "error";
    }
    int i=0;
    LinkList p=L->next;
    while (p){
    p=p->next;
    i++;
    }
    return i;
}
查找倒数第K个节点。
//查找倒数第K个节点。设立双指针,先让第一个遍历到第k个节点,与此同时,第二个指针开始从头遍历,当第一个节点到尾部时,第二个节点即为倒数第k个节点
LNode* FindNodeReverse(LinkList L, int k)
{
    if (L == NULL || k == 0)
    {
        throw "error";
    }

    LinkList p = L->next;
    LinkList q = L->next;
    int i = 0;
    while(p && i < k)
    {
        i++;
        p = p->next;
    }

    if (i < k)
    {
        return NULL;
    }
    else
    {
        while(p)
        {
            p = p->next;
            q = q->next;
        }
        return q;
    }
}
查找单链表中间元素,即第(n/2+1)个结点。
//查找单链表中间元素,即第(n/2+1)个结点。
LNode* FindMiddleNode(LinkList L)
{
    if (L == NULL)
    {
        throw "error";
    }
    if (L->next == NULL)
    {
        return NULL;
    }

    LinkList p1 = L;
    LinkList p2 = L;
    
    while(p1 && p2)
    {
        p1 = p1->next;
        p2 = p2->next;
        if (p2)
        {
            p2 = p2->next;
        }
    }
    return p1;
}
从尾到头打印单链表,使用栈
// 从尾到头打印单链表,使用栈
void VisitListReverse_Stack(LinkList L)
{
    if (L == NULL)
    {
        throw "error";
    }
    stack<LNode> s;
    LinkList p = L;
    while(p)
    {
        s.push(*p);
        p = p->next;
    }

    while(!s.empty())
    {
        cout<<((s.top()).data)<<' ';
        s.pop();
    }
}
从尾到头打印单链表,递归
// 从尾到头打印单链表,递归
void VisitListReverse_Recur(LinkList L)
{
    if (L == NULL) 
    {
        return;
    }
    else
    {
        VisitListReverse_Recur(L->next);
        cout<<L->data<<' ';
    }
}
判断一个单链表中是否有环。
//判断一个单链表中是否有环。设立快慢指针,快指针一定在环内追赶上慢指针。
bool HasCircle(LinkList L)
{
    if (L == NULL)
    {
        throw "error";
    }

    LinkList p1 = L;
    LinkList p2 = L;

    while(p2->next != NULL && p2->next->next != NULL)
    {
        p1 = p1->next;
        p2 = p2->next->next;

        if (p1 == p2)
        {
            return true;
        }
    }
    return false;
}
已知一个单链表中存在环,求进入环中的第一个节点。
//已知一个单链表中存在环,求进入环中的第一个节点。先判断是否存在环,找出相遇节点,然后将原链表转换为两个相交的链表,一个为从原头结点到相遇节点,另一个为从相遇节点的下一个节点到相遇节点
LNode* FindFirstCircleNode(LinkList L)
{
    if (L == NULL)
    {
        throw "error";
    }

    LinkList p1 = L;
    LinkList p2 = L;

    while(p2->next != NULL && p2->next->next != NULL)
    {
        p1 = p1->next;
        p2 = p2->next->next;

        //先判断是否存在环
        if (p1 == p2)
        {
            LinkList ptr_circle = p1->next;//新链表1的头结点
            int len_circle = 1;
            while(ptr_circle != p1)
            {
                ptr_circle = ptr_circle->next;
                len_circle++;
            }

            LinkList ptr_in = L;//新链表2的头结点
            int len_in = 1;
            while(ptr_in != p1)
            {
                ptr_in = ptr_in->next;
                len_in++;
            }

            //求取1、2两个链表的长度差值
            if (len_circle > len_in)
            {
                int k = len_circle - len_in;
                while (k--)
                {
                    ptr_circle = ptr_circle->next;
                }
            }
            else
            {
                int k =len_in - len_circle;
                while (k--)
                {
                    ptr_in = ptr_in->next;
                }
            }

            //求取第一个相遇节点
            while(ptr_circle != ptr_in)
            {
                ptr_circle = ptr_circle->next;
                ptr_in = ptr_in->next;
            }
            return ptr_circle;
        }
    }
    return NULL;
}
给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted。
//给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted。将待删除节点的下一个节点的内容复制到待删除节点,然后删除待删除节点下一节点
void Delete(LinkList pHead, LNode* pToBeDeleted)
{
    if (pHead == NULL || pToBeDeleted == NULL || pHead == pToBeDeleted)
    {
        throw "error";
    }
    LinkList tmp = pToBeDeleted->next;
    if (tmp != NULL)
    {
        pToBeDeleted->data = pToBeDeleted->next->data;
        pToBeDeleted->next = pToBeDeleted->next->next;
        delete tmp;
    } 
    else//待删除节点为最后一个节点
    {
        tmp = pHead;
        while(tmp->next != NULL && tmp->next->next != NULL)
        {
            tmp = tmp->next;
        }
        tmp->next = NULL;
        delete pToBeDeleted;
    }
}
删除表中所有值大于mink且小于maxk的元素
//已知线性表中的元素以值递增有序排列,并以单链表作存储结构。试写一高效的算法,删除表中所有值大于mink且小于maxk的元素(若表中存在这样的元素),同时释放被删结点空间,并分析你的算法的时间复杂度
int ListDelete_L(LinkList &L,float mink, float maxk){
    if (mink>maxk) return -2;
    LinkList p=L->next, p_pre=L, q;
    while(p && p->data<maxk){
        if(p->data<=mink){
            p_pre=p;
            p=p->next;
        }
        else{
            q=p;
            p=p->next;
            free(q);
        }
    }
    p_pre->next=p;
    return 0;
}
删除表中所有值相同多余元素
//已知线性表中的元素以值递增有序排列,并以单链表作存储结构。试写一高效的算法删除表中所有值相同多余元素。
void ListDelete_LSameNode(LinkList &L){
    LinkList p=L, p_pre=L, q;
    p=p->next;
    while(p->next){
        p_pre=p;
        p=p->next;
        while(p && p_pre->data==p->data){//可能有多个和pre相同的元素,递增p
            p_pre->next=p->next;
            q=p;
            p=p->next;
            free(q);
        }
        if (!p) break;
    }
}
带freq域的双向循环链表上的查找
//带freq域的双向循环链表上的查找
LNode_Dul * Locate_DuList(LinkList_Dul &L,int x){
    LinkList_Dul p=L->next, q=NULL;
    while(p!=L && p->data!=x){
        p=p->next;
    }
    if(p==L) return NULL;
    ++(p->freq);
    q=p->prior;
    while(q!=L && q->freq<p->freq){
        q=q->prior;
    }

    //删除p
    p->prior->next=p->next;
    p->next->prior=p->prior;

    //插入p
    p->next=q->next;//先将用到q->next指针处理完
    q->next->prior=p;

    q->next=p;//然后改变q->next值
    p->prior=q;

    return p;
}

 三、多链表操作

判断两个单链表是否相交
// 判断两个单链表是否相交
bool Intersect(LinkList L1, LinkList L2)
{
    if (L1 == NULL || L2 == NULL)
    {
        throw "error";
    }

    LinkList p1 = L1;
    while(p1->next != NULL)
    {
        p1 = p1->next;
    }

    LinkList p2 = L2;
    while(p2->next != NULL)
    {
        p2 = p2->next;
    }

    if (p1 == p2)
    {
        return true;
    }
    return false;
}
求两个单链表相交的第一个节点
// 求两个单链表相交的第一个节点。先对齐两个链表的当前结点,使之到尾节点的距离相等
LNode* FindFirsrtIntersect(LinkList L1, LinkList L2)
{
    if (L1 == NULL || L2 == NULL)
    {
        throw "error";
    }

    LinkList p1 = L1;
    int len1 = 0;
    while(p1->next != NULL)
    {
        len1++;
        p1 = p1->next;
    }
    int len2 = 0;
    LinkList p2 = L2;
    while(p2->next != NULL)
    {
        len2++;
        p2 = p2->next;
    }

    //如果相交,则求相交节点
    if (p1 == p2)
    {
        if (len1 < len2)
        {
            int i = len2 - len1;
            p2 = L2;
            while(i--)
            {
                p2 = p2->next;
            }
        }
        else
        {
            int i = len1 - len2;
            p1 = L1;
            while(i--)
            {
                p1 = p1->next;
            }
        }

        while(p1 != p2)
        {
            p1 = p1->next;
            p2 = p2->next;
        }
        return p1;
    }
    return NULL;
}
已知两个单链表a 和b 各自有序,把它们合并成一个链表依然有序
// 已知两个单链表a 和b 各自有序,把它们合并成一个链表依然有序
void MergeSortedList(LinkList a,LinkList b,LinkList &c)
{
    if (a == NULL && b == NULL)
    {
        throw "error";
        return;
    }
    else if (b != NULL && a == NULL)
    {
        c = b;
        return;
    }
    else if (a != NULL  && b == NULL)
    {
        c = a;
        return;
    }
    
    LinkList p1 = a;
    LinkList p2 = b;
    LinkList p = NULL; 
    if (p1->data != NULL && p2->data != NULL && p1->data > p2->data)
    {
        p = c = p2;
    }
    else
    {
        p = c = p1;
    }

    p1 = p1->next;
    p2 = p2->next;

    while(p1 && p2)
    {
        if (p1->data > p2->data)
        {
            p->next = p2;
            p = p2;
            p2 = p2->next;
        }
        else
        {
            p->next = p1;
            p = p1;
            p1 = p1->next;
        }
    }

    //连接未遍历的后续节点
    if (p1)
    {
        p->next = p1;
    }
    else
    {
        p->next = p2;
    }
}

  

已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序,递归
// 已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序,递归
LNode* MergeSortedList_Recursive(LinkList pHead1,LinkList pHead2)
{
    if(pHead1 == NULL)  
        return pHead2;  
    if(pHead2 == NULL)  
        return pHead1;  
    LinkList pHeadMerged = NULL;  
    if(pHead1->data < pHead2->data)  
    {  
        pHeadMerged = pHead1;  
        pHeadMerged->next = MergeSortedList_Recursive(pHead1->next, pHead2);  
    }  
    else  
    {  
        pHeadMerged = pHead2;  
        pHeadMerged->next = MergeSortedList_Recursive(pHead1, pHead2->next);  
    }  
    return pHeadMerged; 
}
假设有两个按元素值递增有序排列的线性表A和B,均以单链表作存储结构,请编写算法将A表和B表归并成一个按元素值递减有序(即非递增有序,允许表中含有值相同的元素)排列的线性表C,并要求利用原表(即A表和B表)的结点空间构造C表。
//假设有两个按元素值递增有序排列的线性表A和B,均以单链表作存储结构,请编写算法将A表和B表归并成一个按元素值递减有序(即非递增有序,允许表中含有值相同的元素)排列的线性表C,并要求利用原表(即A表和B表)的结点空间构造C表。
int ListMergeOppose_L(LinkList &A,LinkList &B,LinkList &C){
    LinkList pa=A->next, pb=B->next, pc_pre=NULL, pc, q;
    while(pa || pb){
        if (pa && (!pb || pa->data <= pb->data)){//注意if的条件
            pc=pa;
            q=pa->next;
            pa->next=pc_pre;
            pa=q;
        }
        else{
            pc=pb;
            q=pb->next;
            pb->next=pc_pre;
            pb=q;
        }
        pc_pre=pc;
    }
    C=A;A->next=pc;
    return 0;
}
求元素递增排列的线性表A和B的元素的交集并存入C中
//求元素递增排列的线性表A和B的元素的交集并存入C中
void LinkList_Intersect(LinkList A,LinkList B,LinkList &C){
    LinkList pa=A->next, pb=B->next, pc;
    C=pc=(LNode*)malloc(sizeof(LNode));
    while(pa && pb){
        if (pa->data<pb->data){
            pa=pa->next;            
        }
        else if(pa->data<pb->data){
            pb=pb->next;
        }
        else{
            LinkList pc1=(LNode*)malloc(sizeof(LNode));
            pc->next=pc1;
            pc1->data=pa->data;
            pc1->next=NULL;
            pc=pc1;
            pa=pa->next;
            pb=pb->next;
        }
    }
}
把单链表L的元素(char)按类型分为三个循环链表。
//把单链表L的元素(char)按类型分为三个循环链表。A, B, C为带头结点的单循环链表类型。
int LinkList_Divide(LinkList_C &L, LinkList_C &A, LinkList_C &B, LinkList_C &C){
    LinkList_C s=L->next, a, b, c;
    A=a=(LinkList_C)malloc(sizeof(LNode_C));
    B=b=(LinkList_C)malloc(sizeof(LNode_C));
    C=c=(LinkList_C)malloc(sizeof(LNode_C));
    while(s){
        if (isalpha(s->data))
        {
            a->next=s;
            a=a->next;
        }
        else if(isdigit(s->data)){
            b->next=s;
            b=b->next;
        }
        else{
            c->next=s;
            c=c->next;
        }
        s=s->next;
    }
    a->next=A;
    b->next=B;
    c->next=C;
    return 0;
}
 
所有函数都经过验证,如果大家发现有错误,欢迎留言,谢谢。
原文地址:https://www.cnblogs.com/wentfar/p/2705158.html