IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 408 | 数据结构代码算法题模板技巧 之 单链表 -> 正文阅读

[数据结构与算法]408 | 数据结构代码算法题模板技巧 之 单链表

若有错误,请指出!

?

一、数据结构定义

1.1 单链表结点结构体

typedef struct Lnode{
    Elemtype data;
    struct Lnode *next;    //指向下一个结点的指针
}Lnode,*Linklist;

1.2 双链表结点结构体

typedef struct LNode{
    struct Lnode *prior,*next;
    elemtype data;
}LNode,*Linklist;

二、单链表的基本操作

2.1 头插法(插入到链表头)

注意具体使用时,p的后继丢失。需要保存。

viod HeadInsert(Linklist &L,int key){
    Linklist p = new LNode;
    p->data = key;
    p->next = L->next;       //重点
    L->next = p;             //重点
}

2.2 尾插法(插入到链表尾)

void TailInsert(LinkList &L,int key){
    Linklist p = new LNode;
    p->data = key;
    p->next = NULL;
    Linklist q = L;
    while(!q->next)
        q = q->next;
    q->next = p;
}
        


2.3 删除操作代码

void DeleteNode(Linklist &L,int &key){
    Linklist p,q;
    p = GetElem(L,i-1); //p指向删除位置的前驱结点
    q = p->next;
    key = q->data;
    q->next = p->next;
    free(q);
}

2.2 逆置操作代码

void Rerverse(Linklist &L){
    Linklist p = L->next , q = NULL;
    L->next = NULL;     //断链
    while(!p){
        q = p->next;    //q指向p的后继
        p->next = L->next;  //头插法
        L->next = p; 
        p = q;
    }
}
     

2.3 前后指针代码

2.4 快慢指针代码 —— 获取链表中间结点、检测链表是否有环

????????最简单的方法是,先遍历一遍链表,计算出链表的长度,然后计算出中间节点的位置,然后再遍历一遍,边遍历边计算,直到找到中间节点,这个方法略显啰嗦,最坏的情况需要遍历2次链表,代码如下: ?

????????

????????另一个更灵巧的方法是,用两个指针,慢指针每次走一步,快指针每次走两步,当快指针走到链表的末端(NULL)时,慢指针正好指向了中间节点,代码如下:?

Linklist get_mid(Linklist L){
    if(!L) return NULL;
    Linklist slow = L;
    Linklist fast = L->next;
    while(fast && fast->next){
        fast = fast->next->next;
        slow = slow->next;
        //fast走到末尾时,slow刚好在中间位置
    return slow;
}

三、习题练习

3.1 删除值为x的结点

viod Delete_x(Linklist &L,int x){
    //L为带头结点的单链表,本算法删除L中所有值为x的结点
    Linklist p = L->next, pre = L, q ;   //q用于指向删除结点
    while(p != NULL){
        if(p->data == x){
            q = p;
            pre->next = p->next;
            free(q);
            p = p->next;
         }
        else{
            pre = pre->next;
            p = p->next;
    }
}

3.2 单链表就地逆置

试编写算法将带头结点的单链表就地逆置,所谓“就地”是指辅助空间复杂度为O(1)。

Linklist Reverse(Linklist L){
    Linklist p = L->next,r;  //p工作指针,遍历链表,r为p的后继,防止断链
    L->next = NULL;
    while(p != NULL){
        r = p;   //暂存p的后继
        r->next = L->next;  //头插法
        L->next = r;        //头插法
        p = r;
    }
    return L;    //若使用引用,则不必返回,且函数用void
}

3.3 将链表排序

有一个带头结点的单链表L,设计一个算法使其元素递增有序。

?????????

void sort(Linklist &L){
    //类似插入排序,先构造一个仅含一个结点的有序单链表
    //再依次扫描原单链表剩下的结点,通过比较查找插入结点的前趋,插入有序单链表

    Linklist p=L->next,pre;
    Linklist r = p->next;            //r保存p后继,防止断链
    p->next = NULL;             //构造一个仅含有一个结点的单链表
    p = r;                //从第三个结点开始
    while(p){
        r = p->next;
        pre = L;          //每次都从有序单链表头开始查找
        while(p->data > pre->next->data && pre->next!=NULL)
            //这里直接使用pre->next的值进行查找
            //否则需要单独寻找插入结点前趋
            pre = pre->next;
        p->next = pre->next;
        pre->next = p;
        p = r;
    }
}

3.4 拆分链表

????????

Linklist discreate(Linklist &A){
    Linklist B = new LNode;         //创建B表表头
    B->next =NULL;                  //B表初始化
    Linklist p = A->next;           //p为工作指针
    Linklist ra = A;                //ra始终指向A的尾结点
    while(p){
        ra->next = p;
        ra = ra->next;              //p链到A表尾
        p = p->next;
        if(p){
            p->next = q;            //B表使用头插法,头插后p将断链
            p->next = B->next;
            B->next = p;
            p = q;
        }
    }
    ra->next = NULL;
    return B;
}

3.5 删除链表中的重复元素

????????在一个递增有序的线性表中,有数值相同的元素存在。

????????若存储方式为单链表,设计算法去掉数值相同的元素,使表中不再有重复的元素。

????????例如 (7,10,10,21,30,42,42,42,51,70) 将变为(7,10,21,30,42,51,70)。

void Deletesame(Linklist &L){
    Linklist p = L->next,q;
    if(p == NULL) return;
    while(p->next){
        q = p->next;
        if(p->data == q->data){
            p->next = q->next;
            free(q);
        }
        else
            p = p->next;
    }
}

3.6 将两个递增链表合并成一个递增链表

????????假设有两个按元素值递增次序排列的线性表,均以单链表形式存储。请编写算法将这两个单链表归并为一个按元素值递增次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表。

Linklist merge(Linklist L1,Linklist L2){
    //合并两个递增有序单链表(带头结点),合并后链表递增排列
    Linklist ra = L1->next,rb = L2->next;
    Linklist r = L1;

    while(ra && rb){
        if(ra->data <= L2->data){
            r->next = ra;              //尾插法
            r = r->next;
            ra = ra->next;
        }
        else{
            r->next = rb;
            r = r->next;
            rb = rb->next;
        }
    }
    while(ra){
        r->next = ra;
        r = r->next;
        ra = ra->next;
    }
    while(rb){
        r->next = rb;
        r = r->next;
        rb = rb->next;
    }
    r->next = NULL;
    return L1;
}

3.7 将两个递增链表合并成一个递减链表

????????假设有两个按元素值递增次序排列的线性表,均以单链表形式存储。请编写算法将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表。

Linklist merge(Linklist L1,Linklist L2){
    //合并两个递增有序单链表(带头结点),合并后链表递减排列
    Linklist ra = L1->next,rb = L2->next;
    Linklist r = L1,temp;

    while(ra && rb){
        if(ra->data >= L2->data){
            temp = ra->next;              //头插法
            ra->next = r->next;
            r->next = ra;
            ra = temp;
        }
        else{
            temp = rb->next;              //头插法
            rb->next = r->next;
            r->next = rb;
            rb = temp;
        }
    }
    while(ra){
        temp = ra->next;              
        ra->next = r->next;
        r->next = ra;
        ra = temp;
    }
    while(rb){
        temp = rb->next;  
        rb->next = r->next;
        r->next = rb;
        rb = temp;
    }
    return L1;
}

3.8 判断一个链表是否对称

????????设计一个算法用于判断带头结点的循环双链表是否对称。

bool symmetry(Linklist L){
    Linklist q = L->prior,p = L->next;   //前后指针
    while(q->next != p && p != q){       //表中元素为奇数/偶数
        if(q->data != p->data)
            return false;
        p = p->next;                     //前指针后移
        r = r->prior;                    //后指针前移
    }
    return true;
}

3.9 依次输出链表中结点值最小的元素

????????设有一个带头结点的循环单链表,其结点值均为正整数。

????????设计一个算法,反复找出单链表中结点值最小的结点并输出,然后将该结点从中删除,直到单链表空为止,再删除表头结点。

void Delete_Min(Linklist &L){
    Linklist p,ppre,minp,minpre;
    while(L->next !=L ){             //表不空,循环
        p = L->next;ppre = L;        //ppre指向p前驱
        minp = p;minpre = ppre;
        while(p != L){               //循环一趟,寻找最小结点
            if(p->data < minp->data){
                minp = p;
                minpre = ppre;
            }
            ppre = p;
            p = p->next;
        }
        cout<<minp->data;
        minpre->next = minp->next;
        free(minp);
    }
    free(L);
}

3.10 判断链表中是否存在环

????????经典的做法也是用快慢指针,如果没有环,快指针一定先到达链表的末端(NULL),如果有环,快、慢指针一定会相遇在环中.

????????检测环的入口:经典的做法是先检测是否有环,如果有环,则计算出环的长度,然后使用前后指针(不是快慢指针),所谓的前后指针就是一个指针先出发,走了若干步以后,第二个指针也出发,然后两个指针一起走,当前后指针相遇时,它们正好指向了环的入口.

Linklist FindLoopStart(Linklist head){
    Linklist fast = head,slow = head;
    while(fast!=NULL && fast->next!=NULL){
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)    break;    //相遇
    }
    if(slow==NULL || fast->next!=NULL)
        return NULL;                  //没有环
    Linklist p1 = head,p2 = slow;
    while(p1 != p2){
        p1 = p1->next;
        p2 = p2->next;
    }
    return p1;
}

4、真题

【2009统考真题】单链表 查找倒数第k个元素?

【2012统考真题】找出单词相同后缀?

【2015统考真题】删除单链表绝对值相等结点

【2019统考真题】带头结点单链表+穿插+逆置?


部分代码参考于

干货||链表的技巧和算法总结_指针

408数据结构学习强化——常见数据结构定义和算法总结_江南江南江南丶的博客-CSDN博客

【23考研】408代码题参考模板——链表_深海里的鱼(?ω<)★的博客-CSDN博客

?

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:59:48  更:2022-10-17 12:59:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 2:34:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计