专项练习数据结构之链表

1.链表:单链表,双链表,循环链表

2.单链表

单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。与顺序表不同,链表不限制数据的物理存储状态,换句话说,使用链表存储的数据元素,其物理存储位置是随机的。

各数据元素的指针

数据元素随机存储,并通过指针表示数据之间逻辑关系的存储结构就是链式存储结构。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
结点结构

单链表的建立有头插法、尾插法两种方法。

头插法

单链表是用户不断申请存储单元和改变链接关系而得到的一种特殊数据结构,将链表的左边称为链头,右边称为链尾。头插法建单链表是将链表右端看成固定的,链表不断向左延伸而得到的。头插法最先得到的是尾结点。由于链表的长度是随机的,故用一个while循环来控制链表中结点个数。假设每个结点的值都大于O,则循环条件为输入的值大于o。申请存储空间可使用malloc()函数实现,需设立一申请单元指针,但malloc()函数得到的指针并不是指向结构体的指针,需使用强制类型转换,将其转换成结构体型指针。刚开始时,链表还没建立,是一空链表,head指针为NULL。
链表建立的过程是申请空间、得到数据、建立链接的循环处理过程。

尾插法

若将链表的左端固定,链表不断向右延伸,这种建立链表的方法称为尾插法。尾插法建立链表时,头指针须设立一个搜索指针,向链表右边延伸,则整个算法中应设立三个链表指针,即头指针head、搜索指针p2、申请单元指针pl。尾插法最先得到的是头结点

部分内容转载自http://c.biancheng.net/view/3338.html

链表插入元素

虽然新元素的插入位置不固定,但是链表插入元素的思想是固定的,将新元素插入到指定的位置需要进行以下 2 步操作:
(1)将新结点的 next 指针指向插入位置后的结点;
(2)将插入位置前结点的 next 指针指向插入结点;


三种情况
链表删除元素

从链表中删除指定数据元素时,实则就是将存有该数据元素的节点从链表中摘除,对不再利用的存储空间要及时释放。
因此,从链表中删除数据元素需要进行以下 2 步操作:
(1)将结点从链表中摘下来;
(2)手动释放掉结点,回收被结点占用的存储空间;


链表删除元素
 link * del = temp->next;//单独设置一个指针指向被删除结点,以防丢失
 temp->next = temp->next->next;//删除某个结点的方法就是更改前一个结点的指针域
free(del);//手动释放该结点,防止内存泄漏
链表查找元素

在链表中查找指定数据元素,最常用的方法是:从表头依次遍历表中节点,用被查找元素与各节点数据域中存储的数据元素进行比对,直至比对成功或遍历至链表最末端的 NULL(比对失败的标志)。

链表更新元素

更新链表中的元素,只需通过遍历找到存储此元素的节点,对节点中的数据域做更改操作即可。

3.双链表

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表

双向链表结构示意图

双向,指的是各节点之间的逻辑关系是双向的,但通常头指针只设置一个,除非实际情况需要。
双链表的结点

双向链表添加节点

根据数据添加到双向链表中的位置不同,可细分为以下 3 种情况:

1.添加至表头

将新数据元素添加到表头,只需要将该元素与表头元素建立双层逻辑关系即可。换句话说,假设新元素节点为 temp,表头节点为 head,则需要做以下 2 步操作即可:

  1. temp->next=head; head->prior=temp;
  2. 将 head 移至 temp,重新指向新的表头。例如,将新元素 7 添加至双链表的表头


    添加元素至双向链表的表头
2.添加至表的中间位置

同单链表添加数据类似,双向链表中间位置添加数据需要经过以下 2 个步骤:

  1. 新节点先与其直接后继节点建立双层逻辑关系;
  2. 新节点的直接前驱节点与之建立双层逻辑关系;


    双向链表中间位置添加数据元素
3.添加至表尾

与添加到表头是一个道理,实现过程如下:

  1. 找到双链表中最后一个节点;
  2. 让新节点与最后一个节点进行双层逻辑关系;


    双向链表尾部添加数据元素
line * insertLine(line * head,int data,int add){
    //新建数据域为data的结点
    line * temp=(line*)malloc(sizeof(line));
    temp->data=data;
    temp->prior=NULL;
    temp->next=NULL;
    //插入到链表头,要特殊考虑
    if (add==1) {
        temp->next=head;
        head->prior=temp;
        head=temp;
    }else{
        line * body=head;
        //找到要插入位置的前一个结点
        for (int i=1; i<add-1; i++) {
            body=body->next;
        }
        //判断条件为真,说明插入位置为链表尾
        if (body->next==NULL) {
            body->next=temp;
            temp->prior=body;
        }else{
            body->next->prior=temp;
            temp->next=body->next;
            body->next=temp;
            temp->prior=body;
        }
    }
    return head;
}
双向链表删除节点

双链表删除结点时,只需遍历链表找到要删除的结点,然后将该节点从表中摘除即可。例如,删除元素 2 的操作过程如图所示:


双链表删除元素操作示意图
//删除结点的函数,data为要删除结点的数据域的值
line * delLine(line * head,int data){
    line * temp=head;
    //遍历链表
    while (temp) {
        //判断当前结点中数据域和data是否相等,若相等,摘除该结点
        if (temp->data==data) {
            temp->prior->next=temp->next;
            temp->next->prior=temp->prior;
            free(temp);
            return head;
        }
        temp=temp->next;
    }
    printf("链表中无该数据元素");
    return head;
}
双向链表查找节点

通常,双向链表同单链表一样,都仅有一个头指针。因此,双链表查找指定元素的实现同单链表类似,都是从表头依次遍历表中元素。

双向链表更改节点

更改双链表中指定结点数据域的操作是在查找的基础上完成的。实现过程是:通过遍历找到存储有该数据元素的结点,直接更改其数据域即可。

4.循环链表

无论是静态链表还是动态链表,有时在解决具体问题时,需要我们对其结构进行稍微地调整。比如,可以把链表的两头连接,使其成为了一个环状链表,通常称为循环链表。只需要将表中最后一个结点的指针指向头结点,链表就能成环



需要注意的是,虽然循环链表成环状,但本质上还是链表,因此在循环链表中,依然能够找到头指针和首元节点等。所以,不要随意改变头指针的指向。在使用循环链表时,附带最多的操作就是遍历链表。

5.静态链表

静态链表,也是线性存储结构的一种,它兼顾了顺序表和链表的优点于一身,可以看做是顺序表和链表的升级版。使用静态链表存储数据,数据全部存储在数组中(和顺序表一样),但存储位置是随机的,数据之间"一对一"的逻辑关系通过一个整形变量(称为"游标",和指针功能类似)维持(和链表类似)。


静态链表存储数据

通过 "数组+游标" 的方式存储具有线性关系数据的存储结构就是静态链表。
静态链表会将第一个数据元素放到数组下标为 1 的位置(a[1])中。从 a[1] 存储的数据元素 1 开始,通过存储的游标变量 3,就可以在 a[3] 中找到元素 1 的直接后继元素 2;同样,通过元素 a[3] 存储的游标变量 5,可以在 a[5] 中找到元素 2 的直接后继元素 3,这样的循环过程直到某元素的游标变量为 0 截止(因为 a[0] 默认不存储数据元素)。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容