day16

一、双向链表

1.1 概念

1 > 所谓双向链表,就是从任意一个节点既能存储其前驱节点信息也能存储后继节点信息

2 > 节点结构体中增加一个指向前驱节点的指针
                                                                                                         

    struct Node
{
    union
    {
        int len;       //头结点数据域
        datatype data; //普通节点数据域
    };
    struct Node *prio; //指向前驱节点的指针
    struct Node *next; //指向后继节点的指针
};
3 > 头结点没有前驱,最后一个节点没有后继

1.2 创建双向链表

1 > 参数:不需要,只需要从堆区申请出一个头结点大小的空间,就创建了一个双向链表

2 > 返回值:返回堆区空间中头结点的地址即可

3 > 注意:需要将头结点数据域初始化为0,两个指针域分别初始化为NULL
                                                                                                                                                      

                                                                                                                                                               //创建双向链表
                                                                                                                                                           
                                                                                                                                                               NodePtr list_create()
{
    //在堆区申请一个头结点
    NodePtr L = (NodePtr)malloc(sizeof(Node));
    if (NULL == L) //if(L = NULL)
    {
        printf("创建失败\n");
        return NULL;
    }

    //说明链表创建成功
    L->len = 0;     //链表长度为0
    L->prio = NULL; //前驱指针为空
    L->next = NULL; //后继指针为空

    printf("创建成功\n");
    return L;
}

1.3 判空

1 > 跟单向链表的判空一致,只需要判断头结点的指针域是否为空即可
               

    //链表判空
    int
    list_empty(NodePtr L)
{
    return L->next == NULL;
}

1.4 申请节点封装数据
 

            //申请节点封装数据
            NodePtr
            apply_node(datatype e)
{
    //申请节点空间的大小
    NodePtr p = (NodePtr)malloc(sizeof(Node));
    if (NULL == p)
    {
        printf("节点申请失败\n");
        return NULL;
    }

    //给节点赋值
    p->data = e;
    p->prio = NULL;
    p->next = NULL;

    return p;
}

2.5 头插

1 > 参数:链表、要插入的元素

2 > 返回值:int 3 > 注意:对于空链表和非空链表的插入,有所不同,并且不能合并
                                                           

    //链表头插
    int
    list_insert_head(NodePtr L, datatype e)
{
    //判断逻辑
    if (NULL == L)
    {
        printf("插入失败\n");
        return -1;
    }

    //申请节点封装数据
    NodePtr p = apply_node(e);
    if (NULL == p)
    {
        return -1;
    }

    //头插逻辑
    if (list_empty(L))
    { //链表为空时的插入逻辑
        p->prio = L;
        L->next = p;
    }
    else
    {
        //链表非空时的插入
        p->prio = L;
        p->next = L->next;
        L->next->prio = p; //p->next->prio=p;
        L->next = p;
    }

    printf("插入成功\n");

    L->len++; //链表长度变化

    return 0;
}

2.6 链表遍历

1 > 参数:链表

2 > 返回值:int

3 > 注意:需要使用一个遍历指针,从第一个节点出发,到最后一个节点
                                                

    //链表遍历
    int
    list_show(NodePtr L)
{
    //判断逻辑
    if (NULL == L || list_empty(L))
    {
        printf("遍历失败\n");
        return -1;
    }

    //遍历逻辑
    NodePtr q = L->next; //从第一个节点出发
    while (q)
    {
        //输出数据域
        printf("%c\t", q->data);

        //遍历指针后移
        q = q->next;
    }
    printf("\n");
}

3.7 按位置查找节点

1 > 参数:链表、要查找的位置

2 > 返回值:成功返回找到的结点,失败返回NULL
                                                

  //按位置查找返回节点    

NodePtr list_search_pos(NodePtr L, int pos)
{
    //判断逻辑
    if (NULL == L || list_empty(L) || pos < 0 || pos > L->len)
    {
        printf("查找失败\n");
        return NULL;
    }

    //查找逻辑
    NodePtr q = L; //定义遍历指针从头结点出发
    for (int i = 0; i < pos; i++)
    {
        q = q->next;
    }

    //返回节点
    return q;
}

3.8 任意位置删除

1 > 参数:链表、要删除的位置

2 > 返回值 : int 3 > 注意:对于双向链表的任意位置进行操作时(插入、删除),可以找到前驱结点处理也可以不用找到前驱结点
                                                                 

 //链表任意位置删除
int list_delete_pos(NodePtr L, int pos)
{
    //判断逻辑
    if (NULL == L || list_empty(L) || pos < 1 || pos > L->len)
    {
        printf("删除失败\n");
        return -1;
    }

    //找到要删除的节点
    NodePtr q = list_search_pos(L, pos);

    //删除逻辑
    if (q->next == NULL)
    {
        //表示q为最后一个节点
        q->prio->next = NULL;
    }
    else
    {
        //上传下达
        q->prio->next = q->next;
        q->next->prio = q->prio;
    }

    free(q); //释放自己
    q = NULL;

    printf("删除成功\n");
    //表长变化
    L->len--;

    return 0;
}

3.9 销毁链表

1 > 参数:链表

2 > 返回值:int

3 > 注意:需要将所有的节点,全部删除后,然后删除头结点
                                                  

    //链表删除
    void list_destroy(NodePtr L)
{
    //判断逻辑
    if (NULL == L)
    {
        printf("删除失败\n");
        return;
    }

    //删除所有节点
    while (!list_empty(L))
    {
        list_delete_pos(L, 1);
    }

    //删除头结点
    free(L);
    L = NULL;

    printf("链表释放成功\n");
}

1.10 代码汇总

1 >

doublelinklist.h
                     

#ifndef DOUBLELINKLIST_H
#define DOUBLELINKLIST_H
#include <myhead.h>

 typedef char datatype; //数据域的类型

//定义节点类型
typedef struct Node
{
    union
    {
        int len;       //头节点数据域
        datatype data; //普通节点数据域
    };

    struct Node *prio; //前驱指针
    struct Node *next; //后继指针
} Node, *NodePtr;

//创建双向链表
NodePtr list_create();

//链表判空
int list_empty(NodePtr L);

//申请节点封装数据
NodePtr apply_node(datatype e);

//链表头插
int list_insert_head(NodePtr L, datatype e);

//链表遍历
int list_show(NodePtr L);

//按位置查找返回节点
NodePtr list_search_pos(NodePtr L, int pos);

//链表任意位置删除
int list_delete_pos(NodePtr L, int pos);

//链表删除
void list_destroy(NodePtr L);

#endif

2 > doublelinklist.c
        Plain Text
            自动换行

#include "doublelinklist.h"

                //创建双向链表
                NodePtr
                list_create()
{
    //在堆区申请一个头结点
    NodePtr L = (NodePtr)malloc(sizeof(Node));
    if (NULL == L) //if(L = NULL)
    {
        printf("创建失败\n");
        return NULL;
    }

    //说明链表创建成功
    L->len = 0;     //链表长度为0
    L->prio = NULL; //前驱指针为空
    L->next = NULL; //后继指针为空

    printf("创建成功\n");
    return L;
}

//链表判空
int list_empty(NodePtr L)
{
    return L->next == NULL;
}

//申请节点封装数据
NodePtr apply_node(datatype e)
{
    //申请节点空间的大小
    NodePtr p = (NodePtr)malloc(sizeof(Node));
    if (NULL == p)
    {
        printf("节点申请失败\n");
        return NULL;
    }

    //给节点赋值
    p->data = e;
    p->prio = NULL;
    p->next = NULL;

    return p;
}

//链表头插
int list_insert_head(NodePtr L, datatype e)
{
    //判断逻辑
    if (NULL == L)
    {
        printf("插入失败\n");
        return -1;
    }

    //申请节点封装数据
    NodePtr p = apply_node(e);
    if (NULL == p)
    {
        return -1;
    }

    //头插逻辑
    if (list_empty(L))
    { //链表为空时的插入逻辑
        p->prio = L;
        L->next = p;
    }
    else
    {
        //链表非空时的插入
        p->prio = L;
        p->next = L->next;
        L->next->prio = p; //p->next->prio=p;
        L->next = p;
    }

    printf("插入成功\n");

    L->len++; //链表长度变化

    return 0;
}

//链表遍历
int list_show(NodePtr L)
{
    //判断逻辑
    if (NULL == L || list_empty(L))
    {
        printf("遍历失败\n");
        return -1;
    }

    //遍历逻辑
    NodePtr q = L->next; //从第一个节点出发
    while (q)
    {
        //输出数据域
        printf("%c\t", q->data);

        //遍历指针后移
        q = q->next;
    }
    printf("\n");
}

//按位置查找返回节点
NodePtr list_search_pos(NodePtr L, int pos)
{
    //判断逻辑
    if (NULL == L || list_empty(L) || pos < 0 || pos > L->len)
    {
        printf("查找失败\n");
        return NULL;
    }

    //查找逻辑
    NodePtr q = L; //定义遍历指针从头结点出发
    for (int i = 0; i < pos; i++)
    {
        q = q->next;
    }

    //返回节点
    return q;
}

//链表任意位置删除
int list_delete_pos(NodePtr L, int pos)
{
    //判断逻辑
    if (NULL == L || list_empty(L) || pos < 1 || pos > L->len)
    {
        printf("删除失败\n");
        return -1;
    }

    //找到要删除的节点
    NodePtr q = list_search_pos(L, pos);

    //删除逻辑
    if (q->next == NULL)
    {
        //表示q为最后一个节点
        q->prio->next = NULL;
    }
    else
    {
        //上传下达
        q->prio->next = q->next;
        q->next->prio = q->prio;
    }

    free(q); //释放自己
    q = NULL;

    printf("删除成功\n");
    //表长变化
    L->len--;

    return 0;
}

//链表删除
void list_destroy(NodePtr L)
{
    //判断逻辑
    if (NULL == L)
    {
        printf("删除失败\n");
        return;
    }

    //删除所有节点
    while (!list_empty(L))
    {
        list_delete_pos(L, 1);
    }

    //删除头结点
    free(L);
    L = NULL;

    printf("链表释放成功\n");
}

3 > main.c
      

#include "doublelinklist.h"

    int main(int argc, const char *argv[])
{
    //调用创建函数
    NodePtr L = list_create();
    if (NULL == L)
    {
        return -1;
    }

    //调用头插函数
    list_insert_head(L, 'Q');
    list_insert_head(L, 'W');
    list_insert_head(L, 'E');
    list_insert_head(L, 'R');
    list_insert_head(L, 'D');
    list_insert_head(L, 'F');

    //调用遍历函数
    list_show(L);

    //调用任意位置删除函数
    list_delete_pos(L, 1);
    list_delete_pos(L, 3);
    list_delete_pos(L, L->len);

    list_show(L);

    //释放链表
    list_destroy(L);
    L = NULL;

    list_show(L);

    return 0;
}

二、循环链表

2.1 概念

1 > 循环链表,就是首尾相接的链表。

2 > 单向循环链表:只需要将最后一个节点的指针域指向头结点即可

3 > 双向循环链表:需要将最后一个阶段的指针域指向头结点,头结点的前驱指针指向最后一个阶段

 2.2 单向链表操作

1 > 节点结构体
                        

    //定义数据类型
    typedef int datatype;

//定义结点类型
typedef struct Node
{
    union
    {
        int len;       //头结点数据域
        datatype data; //普通结点数据域
    };

    struct Node *next; //指针域
};

2 > 链表的创建
        注意:创建头结点后,需要将头结点的指针域指向头结点自身
        

                    //创建循环链表
                    NodePtr
                    list_create()
{
    //在堆区申请一个头结点
    NodePtr L = (NodePtr)malloc(sizeof(Node));
    if (NULL == L)
    {
        printf("创建失败\n");
        return NULL;
    }

    //初始化
    L->len = 0;
    L->next = L; //头结点指针域指向自己

    printf("创建成功\n");
    return L;
}

3 > 链表判空
        Plain Text
            自动换行

    //链表判空
    int
    list_empty(NodePtr L)
{
    return L->next == L;
}

4 > 申请节点封装数据
        Plain Text
            自动换行

                //链表申请空间封装节点
                NodePtr
                apply_node(datatype e)
{
    //堆区申请一个节点的空间
    NodePtr p = (NodePtr)malloc(sizeof(Node));
    if (NULL == p)
    {
        printf("申请失败\n");
        return NULL;
    }

    //给节点赋值
    p->data = e;
    p->next = NULL;

    return p;
}

5 > 按位置查找节点
        Plain Text
            自动换行

                //按位置进行查找
                NodePtr
                list_search_pos(NodePtr L, int pos)
{
    //判断逻辑
    if (NULL == L || pos < 0 || pos > L->len)
    {
        printf("查找失败\n");
        return NULL;
    }

    //查找逻辑
    NodePtr q = L;
    for (int i = 0; i < pos; i++)
    {
        q = q->next;
    }

    return q;
}

6 > 尾插
        Plain Text
            自动换行

    //链表尾插
    int
    list_insert_tail(NodePtr L, datatype e)
{
    //判断逻辑
    if (NULL == L)
    {
        printf("插入失败\n");
        return -1;
    }

    //找到最后一个节点
    NodePtr q = list_search_pos(L, L->len);

    //封装节点
    NodePtr p = apply_node(e);
    if (NULL == p)
    {
        return -1;
    }

    //插入逻辑
    p->next = q->next;
    q->next = p;

    //表的变化
    L->len++;
    printf("插入成功\n");
    return 0;
}

7 > 链表遍历
        Plain Text
            自动换行

    //链表遍历
    int
    list_show(NodePtr L)
{
    //判断逻辑
    if (NULL == L || list_empty(L))
    {
        printf("遍历失败\n");
        return -1;
    }

    //遍历逻辑
    NodePtr q = L->next;
    while (q != L)
    {
        printf("%c\t", q->data);
        q = q->next; //继续访问下一个
    }
    printf("\n");
}

8 > 头删
        Plain Text
            自动换行

    //链表的头删
    int
    list_delete_head(NodePtr L)
{
    //判断逻辑
    if (NULL == L || list_empty(L))
    {
        printf("删除失败\n");
        return -1;
    }

    //头删逻辑
    NodePtr p = L->next; //标记
    L->next = p->next;   //孤立
    free(p);             //删除
    p = NULL;

    //表长变化
    L->len--;
    printf("删除成功\n");
    return 0;
}

9 > 销毁链表
        Plain Text
            自动换行

    //链表销毁
    void
    list_destroy(NodePtr L)
{
    //判断逻辑
    if (NULL == L)
    {
        printf("释放失败\n");
        return;
    }

    //删除节点
    while (!list_empty(L))
    {
        list_delete_head(L);
    }

    //释放头结点
    free(L);
    L = NULL;
    printf("销毁成功\n");
}

三、操作受限的线性表


1>    在之前的内容,无论是顺序表还是链表,都是详细处理的线性表,既可以在端点处进行操作,也可以在中间位置操作
2>    现实生活中,有很多并不需要在中间进行操作的序列,只在端点处进行操作,这样的线性表,我们称为操作受限的线性表
3>    根据不同的受限情况,线性表分为:栈、队列
4>    栈:插入和删除操作都只允许在同一端进行。
   队列:插入和删除操作都只允许在异端进行。


 
四、栈


4.1    栈的相关概念


1>    栈:操作受限的线性表,插入和删除只能在同一端进行,不能在中间进行相关操作
2>    允许操作的一端,称为栈顶,不允许操作的一端称为栈底
3>    特点:先进后出(后进先出)
例如:水杯容器、枪的弹夹
4>    栈的分类:根据存储方式的不同,分为顺序栈和链式栈
顺序栈:顺序存储的栈称为顺序栈
链式栈:链式存储的栈称为链式栈


2.2    顺序栈


1>    原理图

2>    结构体类型
 

typedef int datatype;   //数据类型
#define MAX 8           //顺序栈最大容量
//定义顺序栈的类型
typedef struct 
{
    datatype *data;      //存储栈的容器,指向堆区空间
    int top;             //记录栈顶元素的下标
}Stack, *StackPtr;
 
 


3>    创建栈


创建栈空间后,还需要为栈申请存储空间
 

//创建栈
StackPtr stack_create()
{
    //在堆区申请一个栈的大小
    StackPtr S = (StackPtr)malloc(sizeof(Stack));
    if(NULL == S)
    {
        printf("创建失败\n");
        return NULL;
    }
 
    //程序执行至此,表示栈申请出来了,但是
    //存储栈的空间还没有申请
    S->data = (datatype *)malloc(sizeof(datatype) * MAX);
    if(NULL == S->data)
    {
        printf("创建失败\n");
        return NULL;
    }
    //给空间内容初始化
    //memset(S->data, 0, sizeof(datatype)*MAX);
    bzero(S->data, sizeof(datatype)*MAX);
    //栈顶元素变量初始化
    S->top = -1;
 
    printf("创建成功\n");
    return S;
}


 
4>    判空、判满
 

//判空
int stack_empty(StackPtr S)
{
    return S->top == -1;
}
 
//判满
int stack_full(StackPtr S)
{
    return S->top == MAX-1;
}


 
5>    入栈
先加后压
 

//入栈:也叫压栈  先加后压
void stack_push(StackPtr S, datatype e)
{
    //判断逻辑
    if(NULL==S || stack_full(S))
    {
        printf("入栈失败\n");
        return ;
    }
    
    //入栈逻辑
    S->top++;            //偏移栈顶位置
    S->data[S->top] = e;  //将数据压入栈中
 
    printf("入栈成功\n");
}
 


6>    出栈
先弹后减
 

//出栈
void stack_pop(StackPtr S)
{
    //判断逻辑
    if(NULL==S || stack_empty(S))
    {
        printf("出栈失败\n");
        return;
    }
 
    //出栈逻辑:先弹后减
    printf("%d出栈成功\n", S->data[S->top]);
    S->top--;   
}


 
7>    遍历栈
本质上是数组的遍历
 

//遍历栈
void stack_show(StackPtr S)
{
    //判断逻辑
    if(NULL==S || stack_empty(S))
    {
        printf("遍历失败\n");
        return ;
    }
 
    printf("从栈顶到栈底元素分别是:");
    for(int i=S->top; i>=0; i--)
    {
        printf("%d\t", S->data[i]);
    }
    printf("\n");
}
 
8>    获取栈顶元素的地址
Plain Text
自动换行

//获取栈顶元素
datatype* stack_get_top(StackPtr S)
{
    //判断逻辑
    if(NULL==S || stack_empty(S))
    {
        printf("操作失败\n");
        return NULL;
    }
 
    return &S->data[S->top];   //返回值栈顶元素地址
}


 
9>    求栈的大小
本质上就跟top有关
 

//求栈的大小
int stack_size(StackPtr S)
{
    //判断逻辑
    if(NULL==S)
    {
        printf("操作失败\n");
        return -1;
    }
 
    //返回大小
    return S->top+1;
}
 


 
10>    销毁栈
先销毁容器,再销毁栈
 

//销毁栈
void stack_destroy(StackPtr S)
{
    if(S != NULL)
    {
        //销毁栈的容器
        free(S->data);
        S->data = NULL;
 
        //销毁栈
        free(S);
        S = NULL;
    }
    printf("销毁成功\n");
}
 

4.3    代码汇总
1>    seqstack.h
 

#ifndef SEQSTACK_H
#define SEQSTACK_H
#include<myhead.h>
 
typedef int datatype;   //数据类型
#define MAX 8           //顺序栈最大容量
//定义顺序栈的类型
typedef struct 
{
    datatype *data;      //存储栈的容器,指向堆区空间
    int top;             //记录栈顶元素的下标
}Stack, *StackPtr;
 
//创建栈
StackPtr stack_create();
 
//判空
int stack_empty(StackPtr S);
 
//判满
int stack_full(StackPtr S);
 
//入栈
void stack_push(StackPtr S, datatype e);
 
//出栈
void stack_pop(StackPtr S);
 
//遍历栈
void stack_show(StackPtr S);
 
//获取栈顶元素
datatype* stack_get_top(StackPtr S);
 
//求栈的大小
int stack_size(StackPtr S);
 
//销毁栈
void stack_destroy(StackPtr S);
 
 
#endif
 
2>    seqstack.c
Plain Text
自动换行

#include"seqstack.h"
 
//创建栈
StackPtr stack_create()
{
    //在堆区申请一个栈的大小
    StackPtr S = (StackPtr)malloc(sizeof(Stack));
    if(NULL == S)
    {
        printf("创建失败\n");
        return NULL;
    }
 
    //程序执行至此,表示栈申请出来了,但是
    //存储栈的空间还没有申请
    S->data = (datatype *)malloc(sizeof(datatype) * MAX);
    if(NULL == S->data)
    {
        printf("创建失败\n");
        return NULL;
    }
    //给空间内容初始化
    //memset(S->data, 0, sizeof(datatype)*MAX);
    bzero(S->data, sizeof(datatype)*MAX);
    //栈顶元素变量初始化
    S->top = -1;
 
    printf("创建成功\n");
    return S;
}
 
//判空
int stack_empty(StackPtr S)
{
    return S->top == -1;
}
 
//判满
int stack_full(StackPtr S)
{
    return S->top == MAX-1;
}
 
//入栈:也叫压栈  先加后压
void stack_push(StackPtr S, datatype e)
{
    //判断逻辑
    if(NULL==S || stack_full(S))
    {
        printf("入栈失败\n");
        return ;
    }
    
    //入栈逻辑
    S->top++;            //偏移栈顶位置
    S->data[S->top] = e;  //将数据压入栈中
 
    printf("入栈成功\n");
}
 
//出栈
void stack_pop(StackPtr S)
{
    //判断逻辑
    if(NULL==S || stack_empty(S))
    {
        printf("出栈失败\n");
        return;
    }
 
    //出栈逻辑:先弹后减
    printf("%d出栈成功\n", S->data[S->top]);
    S->top--;   
}
 
//遍历栈
void stack_show(StackPtr S)
{
    //判断逻辑
    if(NULL==S || stack_empty(S))
    {
        printf("遍历失败\n");
        return ;
    }
 
    printf("从栈顶到栈底元素分别是:");
    for(int i=S->top; i>=0; i--)
    {
        printf("%d\t", S->data[i]);
    }
    printf("\n");
}
 
//获取栈顶元素
datatype* stack_get_top(StackPtr S)
{
    //判断逻辑
    if(NULL==S || stack_empty(S))
    {
        printf("操作失败\n");
        return NULL;
    }
 
    return &S->data[S->top];   //返回值栈顶元素地址
}
 
//求栈的大小
int stack_size(StackPtr S)
{
    //判断逻辑
    if(NULL==S)
    {
        printf("操作失败\n");
        return -1;
    }
 
    //返回大小
    return S->top+1;
}
 
 
//销毁栈
void stack_destroy(StackPtr S)
{
    if(S != NULL)
    {
        //销毁栈的容器
        free(S->data);
        S->data = NULL;
 
        //销毁栈
        free(S);
        S = NULL;
    }
    printf("销毁成功\n");
}
 
3>    main.c
Plain Text
自动换行

#include<myhead.h>
#include"seqstack.h"
 
int main(int argc, const char *argv[])
{
    //调用创建寒素,创建一个栈
    StackPtr S = stack_create();
    if(NULL == S)
    {
        return -1;
    }
 
    //调用入栈函数
    stack_push(S, 5);
    stack_push(S, 2);
    stack_push(S, 0);
    stack_push(S, 0);
 
    //调用遍历函数
    stack_show(S);
 
    //调用出栈函数
    stack_pop(S);
    stack_pop(S);
 
    stack_show(S);
 
    //调用销毁函数
    stack_destroy(S);
    S = NULL;
 
    
    return 0;
}


使用循环链表完成约瑟夫环问题

link.h

#ifndef MAX
#define MAX 
#include<myhead.h>
typedef int datatype;
typedef struct node
{
  union
  {
   int len;
   datatype data;
  };
  struct node *q;
}node,*node_ptr;
node_ptr linkc();//创建链表头指针
node_ptr applynode(datatype e);//申请一个堆区空间存放变量e
int empty(node_ptr L);//链表判空
int addlink(node_ptr L,datatype e);//头插
int link_show(node_ptr L);//链表输出
node_ptr link_search(node_ptr L,int pos);//根据位置查找地址
int link_insert(node_ptr L,int pos,datatype e);//任意位置插入数据
int link_delete(node_ptr L);//头删
int link_deletes(node_ptr L,int pos);//任意位置删除
int finds(node_ptr L,datatype e);//根据值查找位置
void destory(node_ptr L);//清空链表
void huan(node_ptr L,int human,int cls);//环
#endif
link.c

#include "link.h"
node_ptr linkc()
{
  node_ptr L = (node_ptr)malloc(sizeof(node));
  if (NULL == L)
  {
    printf("创建失败\n");
    return NULL;
  }
  L->len = 0;
  L->q = L;
  printf("创建成功\n");
  return L;
}
node_ptr applynode(datatype e)
{
  node_ptr l = (node_ptr)malloc(sizeof(node));
  if (l == NULL)
  {
    printf("申请失败\n");
    return NULL;
  }
  l->data = e;
  l->q = NULL;

  return l;
}
int empty(node_ptr L)
{
  return L->q == L;
}
int addlink(node_ptr L, datatype e)
{
  if (L == NULL)
  {
    printf("链表不合法\n");
    return -1;
  }
  node_ptr w = applynode(e);
  if (w == NULL)
  {
    return -1;
  }
  node_ptr p = link_search(L, L->len);
  p->q = w;
  w->q = L;
  L->len++;
  return 0;
}
int link_show(node_ptr L)
{
  if (L == NULL || empty(L))
  {
    printf("遍历失败\n");
    return -1;
  }
  printf("链表中的数据分别是:\n");
  node_ptr P = L->q;
  while (P != L)
  {
    printf("%c\t", P->data);
    P = P->q;
  }
  printf("\n");
  return 0;
}
node_ptr link_search(node_ptr L, int pos)
{
  if (NULL == L || pos < 0 || pos > L->len)
  {
    printf("查找失败\n");
    return NULL;
  }
  node_ptr z = L;
  for (int i = 0; i < pos; i++)
  {
    z = z->q;
  }
  return z;
}
int link_insert(node_ptr L, int pos, datatype e)
{
  if (NULL == L || pos < 1 || pos > L->len + 1)
  {
    printf("插入失败\n");
    return -1;
  }
  node_ptr x = applynode(e);
  if (x == NULL)
  {
    return -1;
  }
  node_ptr w = link_search(L, pos - 1);
  x->q = w->q;
  w->q = x;
  L->len++;
  return 0;
}

int link_deletes(node_ptr L, int pos)
{
  if (NULL == L || empty(L) || pos < 1 || pos > L->len)
  {
    printf("删除失败\n");
    return -1;
  }
  node_ptr w = link_search(L, pos - 1);
  node_ptr s = w->q;
  w->q = s->q;
  free(s);
  s = NULL;
  L->len--;
  printf("删除成功\n");
  return 0;
}
int finds(node_ptr L, datatype e)
{
  if (NULL == L || empty(L))
  {
    printf("查找失败\n");
    return -1;
  }
  node_ptr w = L->q;
  for (int index = 1; index <= L->len; index++)
  {
    if (w->data == e)
    {
      return index;
    }
    w = w->q;
  }
  return -1;
}



void destory(node_ptr L)
{
  if (NULL == L)
  {
    return;
  }
  while (!empty(L))
  {
    link_delete(L);
  }
  free(L);
  L = NULL;
  printf("清空成功\n");
  return;
}

void huan(node_ptr S, int human, int cls)
{
  int sum = 0;//循环计数
  for (int i = 1; i <= human; i++)
  {
    link_insert(S, i, i);//按位编号
  }
  node_ptr X = S;
  while (S->len != 0)//直到S len为0
  {
      if (sum == cls - 1&&finds(S,X->q->data)!=-1)//到循环前一个时且后一个数值可以找到
    {
      printf("%d\t", X->q->data);//打印删除值
      link_deletes(S, finds(S, X->q->data));删除元素
      sum = 0;//重新计数
    }
    else
    {
      X = X->q;//指针到下一个
      if (X == S)//跳过头指针
      {
        X = X->q;
      }
      sum++;//计数+1
    }
  }
}


main.c

#include "hijj.h"
int main()
{
    int human=0,cls=0;//人数及循环最大值
    node_ptr S = linkc();
    printf("请输入人数及次序");
    scanf("%d %d",&human,&cls);
    huan(S,human,cls);
    destory(S);
    return 0;
}

使用栈,完成进制转换

输入:一个整数,进制数

输出:该数的对应的进制数

zai.h

#ifndef MAX
#define MAX  20
#include<myhead.h>
typedef int stu;
typedef struct node
{
 
   int top;
    stu *data;
}node,*node_ptr;
node_ptr linkc();//创建链表头指针
int empty(node_ptr S);
int full(node_ptr S);
void fall(node_ptr S,stu e);
void push(node_ptr S);
void zai_show(node_ptr S);;
stu *getdata(node_ptr S);
int zhanbig(node_ptr S);
int desoply(node_ptr S);
void jingzhi(node_ptr,int N,int M);
#endif
zai.c

#include "zai.h"
node_ptr linkc()
{
    node_ptr S = (node_ptr)malloc(sizeof(node));
    if (NULL == S)
    {
        printf("申请失败");
    }
    S->data = (int *)malloc(sizeof(stu) * MAX);
    if (NULL == S->data)
    {
        printf("创建失败");
    }
    memset(S->data, 0, sizeof(stu) * MAX);
    S->top = -1;
}
int empty(node_ptr S)
{
    return S->top == -1;
}
int full(node_ptr S)
{
    return S->top == MAX - 1;
}
void fall(node_ptr S, stu e)
{
    if (NULL == S || full(S))
    {
        printf("入栈失败");
    }
    S->top++;
    S->data[S->top] = e;
}
void push(node_ptr S)
{
    if (NULL == S || empty(S))
    {
        printf("出栈失败");
    }
    printf("%d出栈成功", S->data[S->top]);
    S->top--;
}
void zai_show(node_ptr S)
{
    if (NULL == S || empty(S))
    {
        printf("遍历失败");
    }
    for (int i = S->top; i >= 0; i--)
    {
        printf("%d\t", S->data[i]);
    }
    printf("\n");
}
stu *getdata(node_ptr S)
{
    if (NULL == S || empty(S))
    {
        printf("返回失败");
        return NULL;
    }
    return &S->data[S->top];
}
int zhanbig(node_ptr S)
{
    if (NULL == S)
    {
        printf("操作失败");
        return -1;
    }
    return S->top + 1;
}
int desoply(node_ptr S)
{
    if (NULL != S)
    {
        free(S->data);
        S->data = NULL;
        free(S);
        S = NULL;
    }
    printf("清空成功");
    return 0;
}
void jingzhi(node_ptr S, int N, int M)
{
    while(N!=0)//N不等于0时进行循环
    {
        fall(S,N%M);头插N/M的余数
        N=N/M;//N/M;
    }
    zai_show(S);//输出
}

main.c

#include"zai.h"
int main()
{
    int N=0,M=0;
    node_ptr P =linkc();
    printf("请输入数字与进制\n");
    scanf("%d",&N);
    scanf("%d",&M);
     jingzhi(P,N,M);
    return 0;
}

  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值