数据结构——单向链表

发布于:2025-08-06 ⋅ 阅读:(13) ⋅ 点赞:(0)

一、数据结构:

①常用的数据存储结构

②算法

③面向对象的编程思想

什么是数据结构?

①、用来组织和存储数据

②程序 = 数据结构 + 算法

二、数据与数据之间的关系

①逻辑结构:数据元素与元素之间的关系

集合:数据元素与数据元素之间平等的集合关系

线性结构:数据元素与元素之间存在一对一的关系(如:顺序表,链表,队列、栈)

树形结构:数据元素与元素之间存在一对多的关系(如:二叉树)

图形结构:数据元素与元素之间存在多对多的关系(如:网状结构)

②物理结构:数据元素在计算机内存中的存储方式

顺序结构:在内存中选用一段连续的内存空间进行存储

Ⅰ数据访问方便(O(1))

Ⅱ插入和删除数据是需要移动大量数据

Ⅲ需要预内存分配

Ⅳ可能造成大量的内存碎片

struct data
{
    char a;
    int b;
};

(原来只需char(一个字节)+ int(四个字节) 即五个字节,但在结构体中则需要八个字节进行存储)

链式结构:可以在内存中选用一段非连续的内存空间进行存储

Ⅰ数据访问时必须要从头遍历

Ⅱ插入和删除数据方便

Ⅲ不需要预内存分配,是一种动态存储方式

索引结构:将要存储的数据的关键字和存储位置之间构建构建一个索引表

散列结构(哈希结构):将数据的存储位置与数据元素之间的关键字建立起对应的关系(哈希函数),根据该关系进行数据的存储和查找

二、单向链表

由数据域和指针域组成结点

链表:对象(存储数据的对象) ——> 属性(变量)、行为(函数)

创建的链表指针指向 phead

接下里将从创建链表对象,插入数据,删除数据,查找数据,修改数据,销毁数据介绍单向链表

①创建链表对象

先建立三个文件分别是 (link .c(用于封装函数),link.h(用于存放函数声明),main.c(创建链表,调用函数进行编译))

在头文件中声明链表:

//链表存储的数据的数据类型
typedef int Date_type_t;

//链表节点类型
typedef struct node
{
    Date_type_t date;
    struct node *pnext;
}Node_t;

//链表的对象类型
typedef struct link
{
    Node_t *phead;
    int clen;
}Link_t;
Link_t *create_link()
{
    Link_t *plink = malloc(sizeof(Link_t));
    {
        if(NULL == plink)
        {
            printf("error!\n");
            return NULL;
        }
    }
    plink -> phead = NULL;
    plink -> clen = 0;
    return plink;
}
#include <stdio.h>
#include "link.h"

int main(int argc,const char *arvg[])
{
    Link_t *plink = create_link();
    if(NULL == plink)
    {
        return -1;
    }
}

②插入数据(需要从堆上开辟空间,即动态分配内存,调用malloc函数)

Ⅰ头插

int insert_link_head(Link_t *plink,Date_type_t date)
{
    Node_t *pnode = malloc(sizeof(Node_t));
    if(NULL == plink )
    {
        printf("error!\n");
        return -1;
    }
    pnode -> date = date;  
    pnode -> pnext = NULL;   //数据初始化
   
    pnode -> pnext = plink ->phead;
    plink -> phead = pnode;

    plink -> clen++;
    return 0;
}//头插

(先使结构体指针指向节点,在于链表产生联系)

Ⅱ 尾插

int insert_link_tail(Link_t *plink,Date_type_t data)
{
    if(plink -> phead == NULL)
    {
        return -1;
    }
    Node_t *ptmp = NULL;
    Node_t *pnode = malloc(sizeof(Node_t));
    if(pnode == NULL)
    {
        return -2;
    }
    pnode -> date = data;
    pnode -> pnext = NULL;
    if(plink -> phead == NULL)//链表为空尾插即头插
    {
       plink -> phead = pnode; 
    }
    else 
    {
        ptmp = plink -> phead; 
        while(ptmp -> pnext != NULL)//利用循环找到最后一个节点
        {
            ptmp = ptmp -> pnext;
        }
    }
    ptmp -> pnext = pnode;//找到最后一个节点插入数据
    
    plink -> clen ++;//扩展链表长度
    return 0;
}//尾插

③遍历链表

void link_for_each(Link_t *plink)
{
    Node_t *ptmp;
    ptmp = plink -> phead;
    while(ptmp != NULL)
    {
        printf("%d\n",ptmp -> date);
        ptmp = ptmp -> pnext;
    }
}

③ 删除

Ⅰ头删

int delate_link_head(Link_t *plink)
{
    Node_t *ptmp = NULL; 
    ptmp = plink-> phead;
    if(plink -> phead == NULL)
    {
        return 0;
    }
    plink -> phead = ptmp -> pnext;
    free(ptmp);
    ptmp = NULL;
    plink -> clen--;
    return 1;
}

Ⅱ尾删

int delate_link_tail(Link_t *plink)
{
    Node_t *ptmp = NULL;
    ptmp = plink -> phead;
    if(ptmp == NULL)
    {
        return -1;
    }
    if(ptmp -> pnext == NULL) //只有一个节点头删
    {
        free(ptmp);
        plink -> phead = NULL;
        plink -> clen = 0;
        return 1;
    }
    while(ptmp -> pnext -> pnext != NULL)//找倒数第二个节点
    {
        ptmp = ptmp -> pnext;
    }
    free(ptmp -> pnext);
    ptmp -> pnext = NULL;
    plink -> clen--;
    return 0;
}//尾删

④查找

Node_t *find_link(Link_t *plink,Data_type_t mydata)
{

    Node_t *ptmp;
    ptmp = plink -> phead;
    while(ptmp != NULL)
    {
        Data_type_t s;
        s = ptmp -> date;
        if(s == mydata)
        {
            break;
        }
        
        ptmp = ptmp -> pnext;
    }
    if(ptmp != NULL)
    {
        return ptmp;
    }
    return NULL; 
}

⑤修改

int change_link(Link_t *plink,Date_type_t olddata,Date_type_t newdata)
{
    Node_t *p = NULL;
    p = find_link(plink,olddata);
    if(p == NULL)
    {
        return -1;
    }
    p -> date = newdata;
    return 0;
}

⑥销毁

void destroy_link_head(Link_t *plink)
    
{
    if(plink -> phead == NULL)
    {
        return;
    }
    Node_t *ptmp = NULL;
    Node_t *pnode = NULL;
    ptmp = plink -> phead;
    while(ptmp != NULL)
    {
        pnode = ptmp -> pnext;
        free(ptmp);
        ptmp = pnode;
    }
    free(plink);
}//销毁链表

三、单向链表基础进阶

①查找中间值


int find_link_middle(Link_t *plink)//计数遍历找中间值
{
    Node_t *ptmp = NULL;
    int counter =  0;
    if(plink -> phead == NULL)
    {
        return -1;
    }
    ptmp = plink -> phead;
    while(ptmp != NULL)
    {
        ++counter;
        ptmp = ptmp -> pnext;
    }
    ptmp = plink -> phead;
    for(int i = 0;i < counter / 2; ++i)
    {
        ptmp = ptmp -> pnext;
    }
    return ptmp -> date;
}
Node_t *find_link_middle2(Link_t *plink) //快慢指针法
{
    if(plink -> phead == NULL)
    {
        return NULL;
    }
    Node_t *pfast = plink -> phead;
    Node_t *pslow = plink -> phead;
    while(pfast != NULL)
    {
        pfast = pfast -> pnext;
        if(pfast == NULL)
        {
            break;
        }
        pfast = pfast -> pnext;
        pslow = pslow -> pnext;
    }
    return pslow;
}

②查倒数第k个节点

Node_t *find_link_random(Link_t *plink,int k)
{
    if(plink -> phead == NULL)
    {
        return NULL;
    }
    
    Node_t *pfast = plink -> phead;
    for(int i = 0; i < k; ++i)
    {
        pfast = pfast -> pnext;
        if(pfast == NULL)
        {
            break;
        }
    }
    Node_t  *pslow = plink -> phead;
    while(pfast)
    {
        pfast = pfast -> pnext;
        pslow = pslow -> pnext;
    }
    return pslow;
}

③链表逆序

void reverse_link(Link_t *plink)
{
    if(plink -> phead == NULL)
    {
        return ;
    }
    Node_t *ptmp = plink -> phead;
    Node_t *pinsert = NULL;
    plink -> phead = NULL;
    while(ptmp)
    {
        pinsert = ptmp;
        ptmp = ptmp -> pnext;
        pinsert -> pnext = plink -> phead ;
        plink -> phead = pinsert;
    }
}

⑤链表排序

void sort_link(Link_t *plink)
{
    if(plink -> phead == NULL)
    {
        return ;
    }
    Node_t *ptmp = plink -> phead -> pnext;
    plink -> phead -> pnext = NULL;
    Node_t *pinsert = NULL;
    while(ptmp != NULL)
    {
        pinsert = ptmp;
        ptmp = ptmp -> pnext;
        if(plink -> phead -> date >= pinsert -> date)
        {
            pinsert -> pnext = plink -> phead;
            plink -> phead = pinsert;
        }
        else
        {
           Node_t *p = plink -> phead;
            while(p -> pnext != NULL && pinsert -> date > p -> pnext -> date)
            {
                p = p -> pnext;
            }
            pinsert -> pnext = p -> pnext;
            p -> pnext = pinsert;
        }
    }

}

⑥判断链表是否有环

Node_t *link_hascycle(Link_t *plink)
{
    if(plink -> phead == NULL)
    {
        return NULL;
    }
    Node_t *pfast = plink -> phead;
    Node_t *pslow = plink -> phead;
    while(pfast != NULL && pfast -> pnext != NULL)
    {
        pfast = pfast -> pnext -> pnext;
        pslow = pslow -> pnext;
        if(pslow == pfast)
        {
            return pslow;
        }
    }
    return NULL;
}

⑦约瑟夫环问题

Node_t *is_link_joseph(Link_t *plink,int n)
{
    if(plink -> phead == NULL)
    {
        return NULL;    
    }
    if(plink -> clen ==1)
    {
        return plink -> phead;
    }
    Node_t *pnode = NULL;
    pnode = plink -> phead;
    
    Node_t *p = NULL;
    p = plink -> phead;
    while(p -> pnext != NULL)
    {
        p = p -> pnext;
    }
    p -> pnext = plink -> phead;
    Node_t *ptmp = NULL;
    ptmp = p;
    while(plink -> clen > 1)
    {
        int i;
        for(i = 0; i < n - 1; ++i)
        {
            ptmp = pnode;
            pnode = pnode -> pnext;
        }
        ptmp -> pnext = pnode -> pnext;
        if(pnode == plink -> phead)
        {
            plink -> phead = pnode -> pnext;
        }
        Node_t *q = pnode;
        pnode = pnode -> pnext;
        free(q);
        plink -> clen--;
    }
    pnode = pnode -> pnext;
    return pnode; 
}


网站公告

今日签到

点亮在社区的每一天
去签到