单项循环链表及带头指针的链表

单项循环链表及其带头指针的链表

对于链表我们要仔细深入的学习它,为何呢,因为他是我们在后面学习非线性数据结构的基础,像后面的树,图等结构都是由链表演变出来的,所以我们这篇博客继续探究链表

带头指针的链表

我们上篇博客讲述了带头节点的链表

如图

单项循环链表及带头指针的链表_第1张图片

然后演示出了一系列公式化的打法

像什么插入删除

//找到前置节点p
//插入
new_node->next=p->next;
p->next=new_node;
//删除
temp=p->next;
p->next=temp->next;
free(temp);

但是我们今天的主角带头指针的链表,你需要考虑的就多了,公式化的打法已经无法满足我们了

看图
单项循环链表及带头指针的链表_第2张图片

那我们是否能复刻之前的打法,一套代码打天下?

肯定不行,你会发现你想要采用头插法一下就要如下

new_node->next=head;
head=new_node;

当你遇见空的头指针的时候还要if一下,看起来就麻烦。

那么有简化一下书写难度的方法吗?

有的兄弟,有的。

我们可引入一个dummy节点,这个节点是一个临时节点,然后将指针的信息临时传入进去,而后我们就可以继续我们的公式化打法处理了,处理完以后再将地址的 值返回。

如图
单项循环链表及带头指针的链表_第3张图片

这样的好处就又回到了之前的公式化的打法,只要我们注意最后的维护就行了

具体的代码如下

带头指针的链表(代码)

结构定义及其接口


#ifndef CHAINLIST_H
#define CHAIN_LIST_H
//带头指针的单向链表,维护节点也是node
#include"common.h"

//定义链表头结构只保存头指针
typedef struct {
    node_t *header;
    int cout;

}ChainList_t;
//表头放到数据区,放到全局变量
//初始化
void initChainList(ChainList_t *table);
//释放空间
void destoryChainList(ChainList_t *table);

//插入
int insertChainListHeader(ChainList_t* table, Element_t data);//头插法
int insertChainListpos(ChainList_t* table,int pos, Element_t data);//按位置插入

//删除
int deleteChainListHeader(ChainList_t* table, Element_t data);

//打印
void showChainList(const ChainList_t* table);

#endif //CHAIN_LIST_H


对操作的具体实现


#include 
#include 
#include "chainList.h"

void initChainList(ChainList_t *table) {
    table->cout=0;
    table->header=NULL;
}

int insertChainListHeader(ChainList_t *table, Element_t data) {
    node_t dummy;//定义临时节点
    dummy.next=table->header;
    node_t*p=&dummy;
    node_t* newnode=(node_t*)malloc(sizeof(node_t));
    if (newnode==NULL) {
        return -1;
    }
    newnode->data=data;
    newnode->next=p->next;
    p->next=newnode;;

    ++table->cout;

    table->header=dummy.next;
    return 0;
}

int insertChainListpos(ChainList_t *table, int pos, Element_t data) {
    node_t dummy;
    dummy.next=table->header;
    //判断边界条件
    if (data<0||pos>table->cout) {
        return -1;
    }
    //寻找到插入位置
    node_t *p=&dummy;
    int node=-1;
    while (node<pos-1) {
        p=p->next;
        node++;
    }
    //插入
    node_t *newnode=(node_t*)malloc(sizeof(node_t));
    newnode->data=data;
    newnode->next=p->next;
    p->next=newnode;
    ++table->cout;
    table->header=dummy.next;
    return 0;

}
int deleteChainListHeader(ChainList_t *table, Element_t data) {
    node_t dummy;
    dummy.next=table->header;
    node_t* p=&dummy;
    while (p->next&&p->next->data!=data) {
        p=p->next;
    }
    //判断是否为空
    if (p->next==NULL) {
        printf("No find");
        return-1;
    }
    //删除
    node_t*node=p->next;
    p->next=node->next;
    free(node);
    table->cout--;
    table->header=dummy.next;

    return 0;


}

void destoryChainList(ChainList_t *table) {
    node_t dummy;
    dummy.next=table->header;
    node_t* p=&dummy;
    node_t*node;
    while (p->next) {
        node=p->next;
        p->next=node->next;
        free(node);
        table->cout--;
    }
        printf("link list number %d",table->cout);

}


void showChainList(const ChainList_t *table) {
    node_t* p=table->header;
    printf("link list number %d\n:",table->cout);
    while (p) {
        printf(" %d ",p->data);
        p=p->next;
    }
    printf("\n");

}


其实说实话跟之前的带链表的头指针一样,只不过需要先申请一个节点对节点做包装,而后维护一下表头指针的数据罢了。

我们再来做一下测试

int text2() {
    ChainList_t stu1;
    initChainList(&stu1);
    for (int i=0;i<10;i++) {
        insertChainListHeader(&stu1,i+100);
    }
    insertChainListpos(&stu1,3,300);
    showChainList(&stu1);
    destoryChainList(&stu1);
    
}

int main() {
    text2();
    return 0;
}

这就是对带头指针的链表的实现

但是如果我们再想提出一个需求,就是链表的最后的一个元素要指向第一个元素应该咋整。

这就是引出我们下一个主题

单项循环链表

单项循环链表

在开始我们的学习之前,我们可以先思考一个对代码

node_t*p=&header;
while(p->next)
{
    p=p->next;
}
……


node_t*p=&header;
while(p)
{
    p=p->next
}

你思考就会发现,这两段代码是站在不同的角度进行遍历的,一个是对自己前一个元素进行看的,一个是对自己本身进行看的。

前者更适合插入和删除,而后者更适合遍历。

但是,一到循环链表这两段代码就不管用了,为啥?因为首尾连接了呗。

很自然的,也有两种循环链表的表示方法,一种是带头指针的,一种是不带头指针的

带头指针的

单项循环链表及带头指针的链表_第4张图片

不带头指针的

单项循环链表及带头指针的链表_第5张图片

很正常的我们先实现带头指针的

单项循环链表代码

结构定义以及函数接口


#ifndef LINKLOOP_H
#define LINKLOOP_H
typedef int Element;
//节点
typedef struct _loop_node {
    Element val;
    struct _loop_node *next;

}loopnode;
//头节点
typedef struct {
    loopnode head;
    loopnode *tail;
    int num;
}LinkLoopList;

//结构操作
//初始化
void initLinkLoopList(LinkLoopList *link_loop);
//插入(头插,尾插)
int insertLinkLoop(LinkLoopList *link_loop, Element val);
int inserLinkLoopRear(LinkLoopList *link_loop, Element val);
//遍历显示
void showLinkLoop(const LinkLoopList *link_loop);
//删除
int deleteLinkLoop(LinkLoopList *link_loop, Element val);
//释放空间不释放表头
void destoryLinkLoopRear(LinkLoopList *link_loop);

#endif //LINKLOOP_H


结构操作的实现


#include "linkLoop.h"
#include 
#include 

void initLinkLoopList(LinkLoopList *link_loop) {
    //循环链表一开始就要指向自己
    link_loop->head.next=link_loop->tail=&link_loop->head;
    link_loop->num=0;

}

int insertLinkLoop(LinkLoopList *link_loop, Element val) {
    //先定义一个新节点
    loopnode*node=malloc(sizeof(loopnode));
    if (node==NULL)
        return -1;
    node->val=val;
    node->next=link_loop->head.next;
    link_loop->head.next=node;

    //判断是否维护尾指针
    if (link_loop->tail==&link_loop->head) {
        link_loop->tail=node;
    }
    link_loop->num++;
    return 0;


}

int inserLinkLoopRear(LinkLoopList *link_loop, Element val) {
    loopnode*node=malloc(sizeof(loopnode));
    if (node==NULL)
        return -1;
    node->val=val;
    node->next=link_loop->tail->next;
    link_loop->tail->next=node;
    link_loop->tail=node;
    link_loop->num++;
    return 0;


}

void showLinkLoop(const LinkLoopList *link_loop) {
    loopnode*node=link_loop->head.next;
    while (node!=&link_loop->head) {
        printf("%d->", node->val);
        node=node->next;
    }
    printf("\n");

}

int deleteLinkLoop(LinkLoopList *link_loop, Element val) {
    loopnode*node=&link_loop->head;
    while (node->next!=&link_loop->head&&node->next->val!=val) {
        node=node->next;
    }
   if (node->next->val==val) {
       loopnode *tmp=node->next;
       node->next=tmp->next;
       free(tmp);
       link_loop->num--;
   }
    else {
        printf("not found%d\n",val);
    }
    return 0;

}

void destoryLinkLoopRear(LinkLoopList *link_loop) {
    loopnode*node=link_loop->head.next;
    while (node!=&link_loop->head) {
        loopnode *tmp=node;
        node=node->next;
        free(tmp);
        link_loop->num--;
    }
    printf("Table %d element\n",link_loop->num);
}


测试函数


#include "linkLoop.h"

void text1() {
    LinkLoopList table;
    initLinkLoopList(&table);

    for (int i = 0; i < 10; i++) {
        inserLinkLoopRear(&table, i+100);

    }
    deleteLinkLoop(&table,101);
    showLinkLoop(&table);
    destoryLinkLoopRear(&table);


}


int main() {
    text1();

    return 0;
}


结构如下

在这里插入图片描述

好了这篇博客到这里就结束了,喜欢的点点赞(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤

你可能感兴趣的:(数据结构,笔记,链表,数据结构)