数据结构学习——3

一、循环链表(约瑟夫环)

alt

源码

/*===============================================
*   文件名称:joseph.c
*   创 建 者:青木莲华     
*   创建日期:2025年07月29日
*   描    述:约瑟夫环
================================================*/
#include <stdio.h>
#include <stdlib.h>

typedef int data_t;
typedef struct Node
{
    data_t data;
    struct Node *next;
}link_t;

//joseph func
void joseph(link_t *head,int k,int m,int len)
{
    link_t *q,*p = head;
    //移动到第k个人
    for(int i = 1 ; i < k ; i++)
    {
        p = p->next;
    }
    printf("出队序列: \n");
    while(p->next != p)
    {
        //开始计数,找到报出m的人的前一个位置,方便删除
        for(int i = 1 ; i < m - 1 ; i++)
        {
            p = p->next;
        }
        //q为要出队的人
        q = p->next;
        //出队的人前驱,连上该人的后继
        p->next = q->next;
        //出队后后继补位上来
        p = p->next;
        //输出出队人的编号
        printf("%4d",q->data);
        free(q);
    }
    printf("\t最后未出队编号: %d",p->data);
    free(p);
    printf("\n");
}
//初始化循环单链表
link_t *joseph_ring_init(int n)
{
    link_t *p,*q,*head = NULL;
    for(int i = 1 ; i <= n ; i++)
    {
        p = (link_t *)malloc(sizeof(link_t));
        p->data = i;
        if(head == NULL)
            head = p;
        else
            q->next = p;
        q = p;
    }
    p->next = head;
    return head;
}

int main(int argc, char *argv[])
{ 
    int n;
    printf(">:");
    scanf("%d",&n); 
    link_t *p,*head = joseph_ring_init(n); 
    p = head;
    for(int i = 0 ; i < n + 10 ; i++)
    {
        printf("%4d",p->data);
        p = p->next;
    }
    printf("\n");
    joseph(head,3,4,n);
    return 0;
} 

运行结果

alt

二、双向链表

每个节点有两个指针,一个用于指向下一个节点,一个用于指向上一个节点。

结构

typedef int data_t;
typedef struct Node
{
	data_t data;
    struct Node *prior;
    struct Node *next;
}dlink_t;

dlink.h

/*===============================================
*   文件名称:dlink.h
*   创 建 者:     
*   创建日期:2025年07月29日
*   描    述:
================================================*/
#ifndef __DLINK_H__
#define __DLINK_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef int data_t;
typedef struct Node
{
    data_t data;
    struct Node *prior,*next;
}dlink_t;

//create
dlink_t *link_create();
//empty
int is_empty(dlink_t *head);
//length
int link_length(dlink_t *head);
//clear
void link_clear(dlink_t *head);
//show
void link_show(dlink_t *head);
//insert
int link_insert(dlink_t *head,data_t data,int pos);
//delete
int link_delete(dlink_t *head,data_t data);
//search
dlink_t *link_search(dlink_t *head,data_t data);
//alter
int link_alter(dlink_t *head,data_t old_val,data_t new_val);

#endif

dlink.c

/*===============================================
*   文件名称:dlink.c
*   创 建 者:青木莲华     
*   创建日期:2025年07月29日
*   描    述:双向循环链表
================================================*/
#include "dlink.h"

dlink_t *link_create()
{
    dlink_t *head = (dlink_t *)malloc(sizeof(dlink_t));
    if(head == NULL)
        return NULL;
    head->next = NULL;
    head->prior = NULL;
    head->data = -1;
    return head;
}

//empty
int is_empty(dlink_t *head)
{
    return head->next == NULL;
}
//length
int link_length(dlink_t *head)
{
    dlink_t *p = head;
    int count = 0;
    while(p != NULL)
    {
        count++;
        p = p->next;
    }
    return count;
}
//clear
void link_clear(dlink_t *head)
{
    if(head->next == NULL)
        return;
    dlink_t *p,*q;
    p = q = head->next;
    while(p->next != NULL)
    {
        q = p;
        p = p->next;
        free(q);
    }
}
//show
void link_show(dlink_t *head)
{
    dlink_t *p = head->next;
    while(p != NULL)
    {
        printf("%4d ",p->data);
        p = p->next;
    }
    printf("\n");
}
//insert
int link_insert(dlink_t *head,data_t data,int pos)
{
    if(pos < 0 || pos > link_length(head))
        return 0;
    dlink_t *p = head;
    while(pos--)
        p = p->next;

    dlink_t *new = (dlink_t *)malloc(sizeof(dlink_t));
    new->data = data;
    //判断是不是在表尾插入
    if(p->next == NULL)
    {
        new->next = NULL;
    }
    else
    {
        p->next->prior = new;
        new->next = p->next;
    }
    p->next = new;
    new->prior = p;
    return 1;
}
//delete
int link_delete(dlink_t *head,data_t data)
{
    if(is_empty(head))
        return 0;
    dlink_t *q,*p = head->next;
    while(p != NULL)
    {
        if(p->data != data)
        {
            p = p->next;
            continue;
        }
        //判断是不是在表尾删除
        q = p;
        if(q->next == NULL)
            q->prior->next = NULL;
        else
        {
            q->next->prior = q->prior;
            q->prior->next = q->next;
        }
        free(q);
        p = p->next;
    }
    return 1;
}
//search
dlink_t *link_search(dlink_t *head,data_t data)
{
    if(is_empty(head))
        return NULL;
    dlink_t *p = head->next;
    while(p != NULL)
    {
        if(p->data == data)
            return p;
        p = p->next;
    }
    return NULL;
}
//alter
int link_alter(dlink_t *head,data_t old_val,data_t new_val)
{
    if(is_empty(head))
        return 0;
    dlink_t *p = link_search(head,old_val);
    if(p == NULL)
    {
        printf("The old_val has not find!\n");
        return 0;
    }
    p->data = new_val;
    return 1;
}

main.c

/*===============================================
*   文件名称:main.c
*   创 建 者:青木莲华     
*   创建日期:2025年07月29日
*   描    述:双向循环链表
================================================*/
#include "dlink.h"

int main(int argc, char *argv[])
{ 
    dlink_t *head = link_create();
    
    for(int i = 0 ; i < 10 ; i++)
        link_insert(head,i+1,i);

    link_insert(head,5,10);
    link_show(head);
    link_delete(head,5);
    link_show(head);

    link_alter(head,3,200);
    link_show(head);
    link_alter(head,100,105);
    return 0;
} 

运行截图

alt

双向链表:弥补了单链表的无法找到前驱的缺点

三、双向循环链表

类型:头结点依旧充当链表的起始位置,但是不参与循环

cycdlink.h

/*===============================================
*   文件名称:cycdlink.h
*   创 建 者:青木莲华 
*   创建日期:2025年07月29日
*   描    述:双向循环链表
================================================*/
#ifndef __CYCDLINK_H__
#define __CYCDLINK_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef int data_t;
typedef struct Node
{
    data_t data;
    struct Node *next,*prior;
}dlink_t;

//create
dlink_t *link_create();
//empty
int is_empty(dlink_t *head);
//length
int link_length(dlink_t *head);
//clear
void link_clear(dlink_t *head);
//show
void link_show(dlink_t *head);
//insert
int link_insert(dlink_t *head,data_t data,int pos);
//delete
int link_delete(dlink_t *head,data_t data);
//search
dlink_t *link_search(dlink_t *head,data_t data);
//alter
int link_alter(dlink_t *head,data_t old_val,data_t new_val);

#endif

cycdlink.c

/*===============================================
*   文件名称:cycdlink.c
*   创 建 者:青木莲华 
*   创建日期:2025年07月29日
*   描    述:双向循环链表
================================================*/
#include "cycdlink.h"

//create
dlink_t *link_create()
{
    dlink_t *head = (dlink_t *)malloc(sizeof(dlink_t));
    if(head == NULL)
        return NULL;
    head->next = NULL;
    head->prior = NULL;
    head->data = -1;
    return head;
}
//empty
int is_empty(dlink_t *head)
{
    return head->next == NULL;
}
//length
int link_length(dlink_t *head)
{
    if(is_empty(head))
        return 0;
    int count = 0;
    dlink_t *p = head->next;
    //遍历计数,在头元素的前驱结束
    while(p != head->next->prior)
    {
        p = p->next;
        count++;
    }
    //记入尾部元素个数
    count += 1;
    return count;
}
//clear
void link_clear(dlink_t *head);
//show
void link_show(dlink_t *head)
{
    if(is_empty(head))
        return;
    dlink_t *p = head->next;
    while(p != head->next->prior)
    {
        printf("%4d ",p->data);
        p = p->next;
    }
    //输出尾元素的data
    printf("%4d\n",p->data);
}
//insert
int link_insert(dlink_t *head,data_t data,int pos)
{
    dlink_t *p = head->next;
    dlink_t *new = (dlink_t *)malloc(sizeof(dlink_t));
    new->data = data;
    //空表直接插入,无需计算pos位置
    if(p == NULL)
    {
        head->next = new;
        new->next = new;
        new->prior = new;
        return 1;
    }
    //根据pos位置往左或右插入
    if(pos < 0)
        while(pos++)            //往左寻找插入位置
            p = p->prior;
    else
        while(pos--)            //往右寻找位置
            p = p->next;
    new->next = p->next;
    p->next->prior = new;
    p->next = new;
    new->prior = p;
    return 1;
}
 
//search
dlink_t *link_search(dlink_t *head,data_t data)
{
    if(is_empty(head))
        return NULL;
    dlink_t *p = head->next;
    while(1)
    {
        if(p->data == data)
            return p;
        //判断是否为尾元素
        if(p == head->next->prior)
            break;
        p = p->next;
    }
    //运行到此处表明完整遍历一遍之后没有找到对应值,返回空
    return NULL;
}
//alter
int link_alter(dlink_t *head,data_t old_val,data_t new_val)
{
    dlink_t *p = link_search(head,old_val);
    if(p == NULL)
        return 0;
    p->data = new_val;
    return 1;
}

//delete
int link_delete(dlink_t *head,data_t data)
{    
    //调用search函数,找到对应的节点
    dlink_t *p = link_search(head,data);
    if(p == NULL)
        return 0;
    //节点个数为1 直接删除
    if(link_length(head) == 1)
    {
        head->next = NULL;
        free(p);
        return 1;
    }
    //删除节点是head->next指向节点
    if(p == head->next)
    {
        head->next = p->next;
    }
    //更改相应前驱、后继
    p->next->prior = p->prior;
    p->prior->next = p->next;
    free(p);
    return 1;
}

main.c

/*===============================================
*   文件名称:main.c
*   创 建 者:青木莲华 
*   创建日期:2025年07月29日
*   描    述:双向循环链表
================================================*/
#include "cycdlink.h"


int main(int argc, char *argv[])
{ 
    dlink_t *head = link_create();
    link_insert(head,0,0);

    for(int i = 1 ; i < 5 ; i++)
        link_insert(head,i,i);
    
    for(int i = -1; i >= -5 ; i--)
        link_insert(head,i,i);
    
    printf("show: ");
    link_show(head);

    printf("test loop: ");
    dlink_t *p = head->next;
    for(int i = 0 ; i < link_length(head)+5;i++)
    {
        printf("%4d ",p->data);
        p = p->next;
    }
    printf("\ndelete Node of head->next: "); 
    link_delete(head,0);
    link_show(head);
    printf("test alter(old_val=3,new_val=50):");
    link_alter(head,3,50);
    link_show(head);
    return 0;
} 

运行截图

alt