数据结构--双向链表

发布于:2025-06-19 ⋅ 阅读:(14) ⋅ 点赞:(0)

按值查找返回位置  

//按值查找返回位置                       
int search_value(node_p H,int value)         
{                                            
    if(H==NULL)                              
    {return;}                                
    if(empty_double(H)){return;}             
    int i;                                   
    node_p p=H->next;                        
    for(i=1;p!=NULL;i++,p=p->next)           
    {                                        
        if(p->data==value)                   
        {                                    
            printf("值的位置是%d\n",i);      
            return i;                        
        }                                    
        printf("双向链表内没有该值\n");      
    }                                        
}                                            

按位置修改元素  

//按位置修改元素                               
void update_pos(node_p H,int pos,int change_value) 
{                                                  
    if(H==NULL){return;}                           
    if(empty_double(H)){return;}                   
    if(pos<=0){return;}                            
    int i;                                         
    node_p p=H;                                    
    for(i=0;i<pos;i++,p=p->next)                   
    {                                              
        if(p==NULL)                                
        {                                          
            printf("插入位置不合理\n");            
        }                                          
    }                                              
    p-data=change_value;                           
}                                                  
  1. 自己实现双向循环链表的代码
    a.创建
    b.创建结点
    c.头插
    d.尾插
    e.按位置插入
    f.头删、尾删、按位置删除
    g.按位置查找返回
  2. 功能函数文件
#include "cycle.h"                         

//1、创建双向循环链表                           
node_p create_cycle()                      
{                                           
    node_p H = (node_p)malloc(sizeof(node));  
    if(H == NULL)                             
        return NULL;                        
    // 正确初始化循环链表
    H->len = 0;                               
    H->next = H;                             // 头节点的next指向自身
    H->pri = H;                              // 头节点的pri指向自身
    return H;                               
}                                           

//2、创建结点                               
node_p create_node(int data)                
{                                           
    node_p new = (node_p)malloc(sizeof(node));
    if(new == NULL)                      
    {
        printf("申请空间失败\n");           
        return NULL;                        
    }
    new->data = data;                    
    // 新节点的next和pri都先指向自身
    new->next = new;                    
    new->pri = new;                    
    return new;                        
}                                           

//3、判空                                   
int empty_cycle(node_p H)                  
{                                           
    if(H == NULL)                             
        return -1;                          
    // 循环链表判空条件:头节点的next是否指向自身
    return H->next == H ? 1 : 0;               
}                                           

//4、头插                                   
void insert_head(node_p H, int value)        
{                                           
    if(H == NULL)                             
    {                                       
        printf("入参为空\n");               
        return;                             
    }                                       
    node_p new = create_node(value);          
    
    // 插入新节点到头部
    new->next = H->next;                      
    new->pri = H;                             
    H->next->pri = new;                       
    H->next = new;                            
    
    H->len++;                                // 更新长度
}                                           

//5.尾插                                    
void insert_tail(node_p H, int value)        
{                                           
    if(H == NULL)                             
        return;                             
    
    node_p new = create_node(value);          
    
    // 插入到尾部(即头节点的前面)
    new->next = H;
    new->pri = H->pri;
    H->pri->next = new;
    H->pri = new;
    
    H->len++;                                // 更新长度
}                                           

//6.输出                                    
void show_cycle(node_p H)                  
{                                           
    if(H == NULL)                             
    {                                       
        printf("入参为空\n");               
        return;                             
    }                                       
    
    if(empty_cycle(H)) {
        printf("链表为空\n");
        return;
    }
    
    // 遍历循环链表,从头节点的下一个节点开始,直到再次回到头节点
    node_p p = H->next;                       
    printf("H->");
    while(p != H)                                
    {                                       
        printf("%d<->", p->data);             
        p = p->next;                          
    }                                       
    printf("H\n");                        // 显示循环回到头节点
}                                           

//7.任意位置插入                            
void insert_pos(node_p H, int pos, int value) 
{                                           
    if(H == NULL)                             
        return;                             
    if(pos <= 0)                              
        return;                             
    
    // 如果pos大于长度,插入到尾部
    if(pos > H->len + 1) {
        insert_tail(H, value);
        return;
    }
    
    int i = 0;
    node_p p = H;
    // 找到pos-1位置的节点
    for(; i < pos-1; i++, p = p->next);                                
    
    node_p new = create_node(value);          
    
    // 插入新节点
    new->next = p->next;                      
    new->pri = p;                             
    p->next->pri = new;                       
    p->next = new;                            
    
    H->len++;                                // 更新长度
}

//8、头删
void dele_head(node_p H)
{
    if(H == NULL || H->next == H)  // 链表为空或只有头节点                             
        return;                             
    
    node_p dele = H->next;
    
    // 调整指针,移除第一个节点
    H->next = dele->next;
    dele->next->pri = H;
    
    free(dele);
    H->len--;
}

//9、尾删
void dele_tail(node_p H)
{
    if(H == NULL || H->next == H)  // 链表为空或只有头节点                             
        return;                             
    
    node_p dele = H->pri;  // 尾节点是头节点的前一个
    
    // 调整指针,移除尾节点
    H->pri = dele->pri;
    dele->pri->next = H;
    
    free(dele);
    H->len--;
}

//10、按位删除
void dele_pos(node_p H, int pos)
{
    if(H == NULL || H->next == H)  // 链表为空                             
        return;
    
    if(pos <= 0 || pos > H->len)   // 位置无效                              
        return;                             
    
    int i = 0;
    node_p p = H->next;  // 从第一个节点开始
    
    // 找到要删除的节点
    for(; i < pos-1; i++, p = p->next);
    
    // 调整指针,移除节点
    p->pri->next = p->next;
    p->next->pri = p->pri;
    
    free(p);
    H->len--;
}

//11、按值查找返回位置
int search_value(node_p H, int value)
{
    if(H == NULL || H->next == H)  // 链表为空
        return -1;
    
    int pos = 1;
    node_p p = H->next;  // 从第一个节点开始
    
    while(p != H) {  // 遍历直到回到头节点
        if(p->data == value)
            return pos;
        p = p->next;
        pos++;
    }
    
    return -1;  // 未找到
}

//12、按位置修改元素
void update_pos(node_p H, int pos, int change_value)
{
    if(H == NULL || H->next == H)  // 链表为空
        return;
    
    if(pos <= 0 || pos > H->len)   // 位置无效
        return;
    
    int i = 0;
    node_p p = H->next;  // 从第一个节点开始
    
    // 找到要修改的节点
    for(; i < pos-1; i++, p = p->next);
    
    p->data = change_value;
}

主函数文件

#include "cycle.h"          
int main()                   
{                            
    node_p H = create_cycle();  // 修正函数名
    if(H == NULL) {
        printf("创建链表失败\n");
        return 1;
    }
    
    insert_head(H, 12);       
    insert_head(H, 23);       
    insert_head(H, 43);       
    show_cycle(H);           // 修正函数名
    
    // 测试插入
    insert_pos(H, 1, 25);    // 在位置1插入25      
    show_cycle(H);           
    
    // 测试删除
    dele_tail(H);            // 修正函数名
    show_cycle(H);           
    
    return 0;                
}                            

头文件

#ifndef __CYCLE_H__                                       
#define __CYCLE_H__                                       
#include <stdio.h>                                         
#include <stdlib.h>                                        

typedef struct node                                        
{                                                          
    union                                                  
    {                                                      
        int len;                                           
        int data;                                          
    };                                                     
    struct node *pri;     //指向前驱结点的指针             
    struct node *next;    //指向后继结点的指针             
} node, *node_p;         // 修改:正确定义指针类型                                              

//1、创建双向循环链表                                          
node_p create_cycle();                                    
//2、创建结点                                              
node_p create_node(int data);                              
//3、判空                                                  
int empty_cycle(node_p H);                                
//4、头插                                                  
void insert_head(node_p H, int value);                      
//5、尾插                                                  
void insert_tail(node_p H, int value);                      
//6、输出                                                  
void show_cycle(node_p H);                                       
//7、任意位置插入                                           
void insert_pos(node_p H, int pos, int value);               
//8、头删                                                   
void dele_head(node_p H);                                  
//9、尾删                                                   
void dele_tail(node_p H);                                
//10、按位置删除                                           
void dele_pos(node_p H, int pos);                           
//11、按值查找返回位置                                     
int search_value(node_p H, int value);                      
//12、按位置修改元素                                       
void update_pos(node_p H, int pos, int change_value);           

#endif                                                     

makefile文件

EXE=link                                     
Objs=$(patsubst %.c,%.o,$(wildcard *.c))
CC=gcc
CFlags=-c -o

all:$(EXE)
$(EXE):$(Objs)                               
    $(CC) $^ -o $@
%.o:%.c
    $(CC) $^ $(CFlags) $@
clean:
    rm *.o $(Objs)

C 语言中,链表和顺序表(数组)是两种常见的数据结构,它们各有优缺点,适用于不同场景。以下是两者的对比:
顺序表(数组)
优点:

随机访问高效:通过下标直接访问元素,时间复杂度为 O (1)。
内存连续:缓存命中率高,适合大量数据的批量处理。
实现简单:无需额外维护指针,代码复杂度低。

缺点:

插入 / 删除效率低:需要移动大量元素,时间复杂度为 O (n)。
固定容量:静态数组大小编译时确定,动态数组扩容需重新分配内存并复制数据。
内存碎片:动态扩容可能导致内存碎片,尤其在频繁增删时。


链表(单链表 / 双链表)
优点:

动态扩展:按需分配内存,适合元素数量不确定的场景。
插入 / 删除高效:只需修改指针,时间复杂度为 O (1)(若已知位置)。
内存利用率高:无需预先分配大块连续内存,避免碎片。

缺点:

随机访问慢:必须从头遍历,时间复杂度为 O (n)。
额外空间开销:每个节点需存储指针域,增加内存消耗。
缓存不友好:节点内存不连续,可能影响性能。
适用场景
顺序表:适用于需要频繁随机访问、元素数量固定或变化不大的场景(如矩阵运算、查找表)。
链表:适用于频繁插入删除、元素数量动态变化的场景(如消息队列、LRU 缓存)


网站公告

今日签到

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