链表(单向链表、双向链表、循环链表)


本文将详细展示单向链表、双向链表、循环链表的构造以及最基本的增删改查。

1.单向链表

1.1单链表的定义

单向链表的每个节点包含一个数据字段和一个指向下一个节点的指针。

typedef int ElemType;  // 定义元素类型为int  
  
typedef struct LNode {  
    ElemType data;  // 节点存储数据
    struct LNode *next;        // 指向下一个节点的指针  
} LNode, *LinkList;          // 定义LNode结构体和LinkList指针类型

这是一个定义链表的数据结构。链表的节点 LNode 包含两个部分:一个用于存储数据的数组 data[Max_Size],以及一个指向下一个节点的指针 next

1.2 链表的初始化与销毁

链表的初始化

 //链表的初始化  
void InitList(LinkList L) {  
	L = (LinkList) malloc(sizeof(LinkList));  
    //next结点置空  
    L->next = NULL;  
}

InitList 函数现在接受一个指向链表头指针的指针,分配内存,并初始化 next 指针将其置空。
销毁链表

void DestroyList(LinkList L) {  
    LinkList p;  
    LinkList q;  
  
    p = L; // p 指向头结点  
    while (p != NULL) {  
        q = p;  
        p = p->next; // 移动 p 到下一个节点  
        free(q); // 释放当前节点 q 的内存  
    }  
    L = NULL; // 将头指针设置为 NULL}

1.3链表的其创建

头插法

//头插法创建链表  
void CreateListF(LinkList L,ElemType e[],int n) {  
    LinkList s;  
    for (int i = 0; i < n; ++i) {  
        s = (LinkList)malloc(sizeof(LNode));  
        s->data = e[i];  
        s->next = L->next;  
        L->next = s;  
    }  
}

尾插法

// 尾插法创建链表  
void CreateListR(LinkList L, ElemType e[], int n) {  
    LinkList s, r;  
    r = L; // 初始化r指针指向头结点  
    for (int i = 0; i < n; ++i) {  
        s = (LinkList)malloc(sizeof(LNode)); // 为新节点分配内存  
        s->data = e[i]; // 将数据赋值给新节点  
        s->next = NULL; // 新节点的next指针初始化为NULL  
        r->next = s; // 将新节点链接到链表的尾部  
        r = s; // 更新r指针到新的尾部节点  
    }  
}

1.4链表的插入

//在第i个位置插入元素e  
void Insert(LinkList L,int i,ElemType e) {  
    int j = 0;  
    LinkList s = (LinkList)malloc(sizeof(LNode));  
    LinkList p = L;  
  
    //遍历链表  
    while (j < i - 1 && p != NULL) {  
        p = p->next;  
        j++;  
    }  
    //执行插入操作  
    s->data = e;  
    s->next = p->next;  
    p->next = s;  
}

1.5链表的删除

//删除第i个位置的元素  
void Delete(LinkList L,int i) {  
    int j = 0;  
    LinkList p = L;  
    LinkList q = NULL;  
  
    //遍历链表  
    while (j < i - 1 && p != NULL) {  
        p = p->next;  
        j++;  
    }  
     q = p->next ;  
    p->next = q->next;  
    free(q);  
}

1.6链表的查找

//查找第i个位置的元素  
ElemType Find(LinkList L,int i) {  
    int j = 0;  
    LinkList p = L;  
  
    //遍历链表  
    while (j < i - 1 && p != NULL) {  
        p = p->next;  
        j++;  
    }  
    if(p == NULL) {  
        return -1;  
    }  
    return p->data;  
}

2. 双向链表

双向链表的每个节点包含三个部分:一个用于存储数据的 data,一个指向前一个节点的指针 prev,以及一个指向后一个节点的指针 next

2.1 双向链表的定义

typedef int ElemType;  // 定义元素类型为int  
  
typedef struct DNode {  
    ElemType data;     // 节点存储数据
    struct DNode *prev;  // 指向前一个节点的指针
    struct DNode *next;  // 指向下一个节点的指针
} DNode, *DLinkList;    // 定义DNode结构体和DLinkList指针类型

2.2 链表的初始化与销毁

双向链表的初始化

// 双向链表的初始化  
void InitDList(DLinkList L) {  
    L = (DLinkList) malloc(sizeof(DLinkList));  
    L->prev = NULL;  // prev指针置空
    L->next = NULL;  // next指针置空
}

销毁双向链表

void DestroyDList(DLinkList L) {  
    DLinkList p = L;  
    DLinkList q;  
    while (p != NULL) {  
        q = p;  
        p = p->next;  
        free(q);  
    }  
    L = NULL;  
}

2.3 双向链表的创建

头插法

// 头插法创建双向链表  
void CreateDListF(DLinkList L, ElemType e[], int n) {  
    DLinkList s;  
    for (int i = 0; i < n; ++i) {  
        s = (DLinkList)malloc(sizeof(DNode));  
        s->data = e[i];  
        s->next = L->next;  
        s->prev = L;  
        if (L->next != NULL) {  
            L->next->prev = s;  
        }  
        L->next = s;  
    }  
}

尾插法

// 尾插法创建双向链表  
void CreateDListR(DLinkList L, ElemType e[], int n) {  
    DLinkList s, r;  
    r = L; // r指向尾部节点
    while (r->next != NULL) {  
        r = r->next;  
    }  
    for (int i = 0; i < n; ++i) {  
        s = (DLinkList)malloc(sizeof(DNode));  
        s->data = e[i];  
        s->next = NULL;  
        s->prev = r;  
        r->next = s;  
        r = s;  
    }  
}

2.4 双向链表的插入

// 在第i个位置插入元素e
void InsertDList(DLinkList L, int i, ElemType e) {  
    int j = 0;  
    DLinkList p = L;  
    DLinkList s = (DLinkList)malloc(sizeof(DNode));  
  
    while (j < i - 1 && p != NULL) {  
        p = p->next;  
        j++;  
    }  
  
    s->data = e;  
    s->next = p->next;  
    if (p->next != NULL) {  
        p->next->prev = s;  
    }  
    s->prev = p;  
    p->next = s;  
}

2.5 双向链表的删除

// 删除第i个位置的元素
void DeleteDList(DLinkList L, int i) {  
    int j = 0;  
    DLinkList p = L;  
  
    while (j < i - 1 && p != NULL) {  
        p = p->next;  
        j++;  
    }  
  
    DLinkList q = p->next;  
    if (q != NULL) {  
        p->next = q->next;  
        if (q->next != NULL) {  
            q->next->prev = p;  
        }  
        free(q);  
    }  
}

2.6 双向链表的查找

// 查找第i个位置的元素
ElemType FindDList(DLinkList L, int i) {  
    int j = 0;  
    DLinkList p = L;  
  
    while (j < i - 1 && p != NULL) {  
        p = p->next;  
        j++;  
    }  
  
    if (p == NULL) {  
        return -1;  
    }  
  
    return p->data;  
}

3. 循环链表

循环链表与单链表的区别在于其尾节点的 next 指针指向链表的头节点,使得整个链表形成一个环。

3.1 循环链表的定义

typedef int ElemType;  // 定义元素类型为int  
  
typedef struct CNode {  
    ElemType data;     // 节点存储数据
    struct CNode *next;  // 指向下一个节点的指针
} CNode, *CLinkList;   // 定义CNode结构体和CLinkList指针类型

3.2 循环链表的初始化与销毁

循环链表的初始化

// 循环链表的初始化
void InitCList(CLinkList L) {  
    L = (CLinkList) malloc(sizeof(CLinkList));  
    L->next = L;  // 循环链表的next指针指向自己
}

销毁循环链表

void DestroyCList(CLinkList L) {  
    CLinkList p = L->next;  
    CLinkList q;  
    while (p != L) {  
        q = p;  
        p = p->next;  
        free(q);  
    }  
    free(L);  
}

3.3 循环链表的创建

头插法

// 头插法创建循环链表
void CreateCListF(CLinkList L, ElemType e[], int n) {  
    CLinkList s;  
    for (int i = 0; i < n; ++i) {  
        s = (CLinkList)malloc(sizeof(CNode));  
        s->data = e[i];  
        s->next = L->next;  
        L->next = s;  
    }  
    s->next = L;  // 形成循环
}

尾插法

// 尾插法创建循环链表
void CreateCListR(CLinkList L, ElemType e[], int n) {  
    CLinkList s, r;  
    r = L;  
    while (r->next != L) {  
        r = r->next  
    }  
    for (int i = 0; i < n; ++i) {  
        s = (CLinkList)malloc(sizeof(CNode));  
        s->data = e[i];  
        s->next = L;  // 新节点的next指向头节点,形成环
        r->next = s;  
        r = s;  
    }  
}

3.4 循环链表的插入

// 在第i个位置插入元素e
void InsertCList(CLinkList L, int i, ElemType e) {  
    int j = 0;  
    CLinkList p = L;  
    CLinkList s = (CLinkList)malloc(sizeof(CNode));  
  
    while (j < i - 1 && p->next != L) {  
        p = p->next;  
        j++;  
    }  
  
    s->data = e;  
    snext = p->next;  
    p->next = s;  
}

3.5 循环链表的删除

// 删除第i个位置的元素
void DeleteCList(CLinkList L, int i) {  
    int j = 0;  
    CLinkList p = L;  
  
    while (j < i - 1 && p->next != L)  
        p = p->next;  
        j++;  
    }  
  
    CLinkList q = p->next;  
    if (q != L) {  
        p->next = q->next;  
        free(q);  
    }  
}

3.6 循环链表的查找

// 查找第i位置的元素
ElemType FindCList(CLinkList L, int i) {  
    int j = 0;  
    CLinkList p = L->next;  
  
    while (j < i - 1 && p != L) {  
        p = p->next;  
        j++;  
    }  
  
    if (p == L) {  
        return -1;  
    }  
  
    return p->data;  
}

以上是链表的一些基本操作,原版代码上传至(https://gitee.com/shi-chengfu)

如果有错误请联系QQ:303613518

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写代码的大学生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值