数据结构--链表

这篇博客介绍了如何实现带头结点的单链表和循环双链表的基本操作,包括在任意位置插入元素、删除元素、链表的反转(递归与迭代方式)以及链表排序。此外,还提供了代码示例,演示了这些操作的详细步骤,并在主函数中展示了实际应用。
摘要由CSDN通过智能技术生成

写的比较简洁,只是实现插入,删除,反转,排序,遍历的功能,没有弄出错反馈,查和改比较简单故没写。

简单尝试了循环双链表

目录

一、带头结点的单链表

1、准备工作

2、任意位置插入元素

2、删除任意结点的元素

3、反转链表(递归)

4、反转链表(迭代)

5、链表排序(逆序)

6、打印链表(迭代)

 7、打印链表(递归)(不建议用)

二、带头结点的循环双链表

1、插入

2、打印

三、全部代码


一、带头结点的单链表

1、准备工作

#define TRUE 1
#define FALSE 0
#define INFEASIBLE - 1
#define OVERFLOW - 2
//本次只用到了这两个宏定义
#define OK 1
#define ERROR 0

typedef int ElemType; //数据的类型
typedef int Status;  //函数的类型,其值是函数结果状态代码

typedef struct LNode
{
    ElemType data;       // 存放结点的数据元素。
    struct LNode *next;  // 指向下一个结点的指针。
}LNode,*LinkList;

2、任意位置插入元素

//难点在于第一个结点(非头结点)和最后一个结点的插入
//特别是不带头结点的不好处理
Status  InsertList( LinkList LL, int n, ElemType e)
{
    //找到第n-1个结点,n=1时为头结点
    LNode *PNode=LL;
    for(int i = 0;i<n-1;i++)
    {
        if(PNode != NULL)
            PNode = PNode->next;
    }

    if(PNode == NULL){
        return ERROR; //超出表长
    }
    //新结点,必须申请动态内存
    LNode *NewNode = (LNode *)malloc(sizeof(LNode));
    NewNode->data = e;
    NewNode->next = NULL;

    NewNode->next = PNode->next;
    PNode->next= NewNode;

    return OK;//插入成功

}

2、删除任意结点的元素

Status DeleteListN( LinkList LL,int n){
    LNode *tmp = LL;

    //拿到n-1
    for(int i = 0;i<n-1;i++){
        if(tmp != NULL){
            tmp = tmp->next;
        }
    }
    tmp->next = (tmp->next)->next;
    printf("将位置 %d的元素删除\n",n);
    free(tmp->next);
    return OK;
}

3、反转链表(递归)

//头结点指向最后一个结点,其余结点指向反向
Status RReverseList(LNode *p,LinkList LL){
    //退出条件
    if(p->next == NULL){
        LL->next = p;
        printf("反转链表(递归)\n");
        return OK;
    }

    RReverseList(p->next,LL);
    LNode *nex = p->next;
    nex->next = p;
    p->next = NULL;
}

4、反转链表(迭代)

Status ReverseList(LinkList LL){
    //当前结点,上一个结点,下一个结点
    LNode *cur,*pre,*nex;
    cur = LL->next;
    pre = NULL;

    while(cur != NULL){
        nex = cur->next;
        cur->next = pre;
        pre = cur;
        cur = nex;
    }
    LL->next = pre;

    printf("反转链表\n");
    return OK;
}

5、链表排序(逆序)

Status SortList(LinkList LL){
    LNode *ctmp = LL->next;
    LNode *ntmp = NULL;
    int data;
    while((ctmp->next) != NULL){
        data = ctmp->data;
        ntmp = ctmp->next;
        while(ntmp != NULL){
            if(data<(ntmp->data)){
                ctmp->data = ntmp->data;
                ntmp->data = data;
                data = ctmp->data;
            }
            ntmp = ntmp->next;
        }
        ctmp = ctmp->next;
    }
    printf("排序\n");
    return OK;
}

6、打印链表(迭代)

void PrintList(LinkList LL)
{

    //不打印头结点
    LNode *tmp = LL->next;

    while(tmp != NULL){
        printf("%d ",tmp->data);
        tmp = tmp->next;
    }
    printf("\n");
}

 7、打印链表(递归)(不建议用)

//传入第一个结点 p = head->next;
void PrintList(LNode *p)
{
    //退出条件
    if(p == NULL){
        printf("\n");
        return;
    }

    //递归实现打印,交换顺序可以逆序打出链表
    printf("%d ",p->data);
    PrintList(p->next);
}

二、带头结点的循环双链表

1、插入

Status InsertDList( DLinkList DLL, int n, ElemType e) {

    DLNode *tmp = DLL;
    int i = 0;
    //拿到n结点即可
    //可以插入的位置为表长+1
    //头结点不计入表长
    while (i<n) {
        if(tmp->next != NULL){
            tmp = tmp->next;
        }
        i++;
        if(tmp->next == DLL && i<n-1){
            printf("位置%d过长\n",n);
            return ERROR;
        }
    }

    DLNode *p = (DLNode *) malloc(sizeof(DLNode));
    p->data = e;

    //当链表为空时
    if(tmp == DLL && tmp->next == NULL){
        p->next = tmp;
        p->prev = tmp;
        tmp->next = p;
        tmp->prev = p;
    }
    else{
        p->next = tmp;
        p->prev = tmp->prev;
        (tmp->prev)->next = p;
        tmp->prev = p;
    }
    return OK;
}

2、打印

void PrintDList(DLinkList DLL){
    DLNode *tmp = DLL->next;//不打印头结点
    while(tmp->next != DLL){
        printf("%d ",tmp->data);
        tmp = tmp->next;
    }
    printf("%d\n",tmp->data);
}

三、全部代码

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

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE - 1
#define OVERFLOW - 2

typedef int ElemType; //数据的类型
typedef int Status;  //函数的类型,其值是函数结果状态代码

typedef struct LNode
{
    ElemType data;       // 存放结点的数据元素。
    struct LNode *next;  // 指向下一个结点的指针。
}LNode,*LinkList;

//双向链表
typedef struct DLNode
{
    ElemType data;       // 存放结点的数据元素。
    struct DLNode *next;  // 指向下一个结点的指针。
    struct DLNode *prev;  // 指向上一个结点的指针。
}DLNode,*DLinkList;

/*单链表*/

// 在链表任意位置插入,要传入链表的地址(增)
Status InsertList( LinkList LL, int n, ElemType e);
//删除指定的元素(删)
Status DeleteListN( LinkList LL,int e);
//反转链表(迭代)
Status ReverseList(LinkList LL);
//反转链表(递归recursive)
Status RReverseList(LNode *p,LinkList LL);
//链表排序
Status SortList(LinkList LL);
// 打印链表中全部的元素。
void PrintList(LinkList LL);

/*双链表*/
// 在链表任意位置插入,要传入链表的地址(增)
Status InsertDList( DLinkList DLL, int n, ElemType e);
//删除指定的元素(删)
Status DeleteDListN( DLinkList DLL,int e);
// 打印链表中全部的元素。
void PrintDList(DLinkList DLL);

int main()
{
    LinkList  LL = (LinkList) malloc(sizeof(LNode));
    LL->next = NULL;

    DLinkList DLL = (DLinkList) malloc(sizeof(DLNode));
    DLL->next = NULL;
    DLL->prev = NULL;

    ElemType e[10] = {2,3,5,6,1,7,4,8,9,10};
    Status s;
    //赋初值
    for(int i = 1;i<11;i++){
        s = InsertList(LL,i,e[i-1]);//s判断是否插入成功
    }
    PrintList(LL);
    printf("单链表操作:\n");
    printf("在第1位插入111\n");
    s =  InsertList(LL,1,111);
    PrintList(LL);

    DeleteListN(LL,1);
    PrintList(LL);

    SortList(LL);
    PrintList(LL);

    ReverseList(LL);
    PrintList(LL);

    RReverseList(LL->next,LL);
    PrintList(LL);

    printf("\n双链表操作:\n");
    for(int i = 1;i<11;i++){
        InsertDList(DLL,i,e[i-1]);
    }
    PrintDList(DLL);
    printf("在第1位插入111\n");
   InsertDList(DLL,1,111);
    PrintDList(DLL);
    printf("在第13位插入222\n");
    InsertDList(DLL,13,222);
    PrintDList(DLL);

    return 0;
}

//难点在于第一个结点(非头结点)和最后一个结点的插入
//特别是不带头结点的不好处理
Status  InsertList( LinkList LL, int n, ElemType e)
{
    //找到第n-1个结点,n=1时为头结点
    LNode *PNode=LL;
    for(int i = 0;i<n-1;i++)
    {
        if(PNode != NULL)
            PNode = PNode->next;
    }

    if(PNode == NULL){
        return ERROR; //超出表长
    }
    //新结点,必须申请动态内存
    LNode *NewNode = (LNode *)malloc(sizeof(LNode));
    NewNode->data = e;
    NewNode->next = NULL;

    NewNode->next = PNode->next;
    PNode->next= NewNode;

    return OK;//插入成功

}

Status DeleteListN( LinkList LL,int n){
    LNode *tmp = LL;

    //拿到n-1
    for(int i = 0;i<n-1;i++){
        if(tmp != NULL){
            tmp = tmp->next;
        }
    }
    tmp->next = (tmp->next)->next;
    printf("将位置 %d的元素删除\n",n);
    free(tmp->next);
    return OK;
}

Status ReverseList(LinkList LL){
    //当前结点 current,上一个结点previous,下一个结点next
    LNode *cur,*pre,*nex;
    cur = LL->next;
    pre = NULL;

    while(cur != NULL){
        nex = cur->next;
        cur->next = pre;
        pre = cur;
        cur = nex;
    }
    LL->next = pre;

    printf("反转链表(迭代)\n");
    return OK;
}

Status RReverseList(LNode *p,LinkList LL){

    if(p->next == NULL){
        LL->next = p;
        printf("反转链表(递归)\n");
        return OK;
    }

    RReverseList(p->next,LL);
    LNode *nex = p->next;
    nex->next = p;
    p->next = NULL;
}

Status SortList(LinkList LL){
    LNode *ctmp = LL->next;
    LNode *ntmp = NULL;
    int data;
    while((ctmp->next) != NULL){
        data = ctmp->data;
        ntmp = ctmp->next;
        while(ntmp != NULL){
            if(data<(ntmp->data)){
                ctmp->data = ntmp->data;
                ntmp->data = data;
                data = ctmp->data;
            }
            ntmp = ntmp->next;
        }
        ctmp = ctmp->next;
    }
    printf("排序\n");
    return OK;
}

// 打印链表中全部的元素。
void PrintList(LinkList LL)
{
    //不打印头结点
    LNode *tmp = LL->next;

    while(tmp != NULL){
        printf("%d ",tmp->data);
        tmp = tmp->next;
    }
    printf("\n");
}

Status InsertDList( DLinkList DLL, int n, ElemType e) {

    DLNode *tmp = DLL;
    int i = 0;
    //拿到n结点即可
    //可以插入的位置为表长+1
    //头结点不计入表长
    while (i<n) {
        if(tmp->next != NULL){
            tmp = tmp->next;
        }
        i++;
        if(tmp->next == DLL && i<n-1){
            printf("位置%d过长\n",n);
            return ERROR;
        }
    }

    DLNode *p = (DLNode *) malloc(sizeof(DLNode));
    p->data = e;

    //当链表为空时
    if(tmp == DLL && tmp->next == NULL){
        p->next = tmp;
        p->prev = tmp;
        tmp->next = p;
        tmp->prev = p;
    }
    else{
        p->next = tmp;
        p->prev = tmp->prev;
        (tmp->prev)->next = p;
        tmp->prev = p;
    }
    return OK;
}

void PrintDList(DLinkList DLL){
    DLNode *tmp = DLL->next;//不打印头结点
    while(tmp->next != DLL){
        printf("%d ",tmp->data);
        tmp = tmp->next;
    }
    printf("%d\n",tmp->data);
}

 封面来源:https://www.bilibili.com/video/BV1Fv4y1f7T1?p=5

视频讲的和我写的有点出入,但可以看思路

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值