✌数据结构——链表

链表的概念

定义:链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实             现的一种线性存储结构(顺序存取)

特点:链表由一系列节点(链表中每一个元素称为节点)组成,节点在运行时动态生成                   (malloc),每个节点包括两个部分:

         (1)存储数据元素的数据域

         (2)存储下一个节点首地址的指针域

eg:     

        1,3,5,7,9

        存储数据元素    1
        1    数据要存储                     int      (数据)
        &3    下一个元素的地址        *        (关系)

        存储数据元素    3
        3    数据要存储                     int      (数据)
        &5    下一个元素的地址        *        (关系)
        ....

链表与数组的对比 (以带头结点的双向循环链表为例)

链表是通过节点把离散的数据链接成一个表,通过对节点的插入和删除操作从而实现对数据的存取。而数组是通过开辟一段连续的内存来存储数据,这是数组和链表最大的区别。数组的每个成员对应链表的节点,成员和节点的数据类型可以是标准的 C 类型或者是 用户自定义的结构体。数组有起始地址和结束地址,而链表是一个圈,没有头和尾之分, 但是为了方便节点的插入和删除操作会人为的规定一个根节点(头节点)

无头结点单链表

LinkedList.h

#ifndef __LINKEDLIST_H__
#define __LINKEDLIST_H__

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

typedef int ElemType;

struct node {
    ElemType data; // 数据域  保存数据
    struct node *next; // 指针域 保存逻辑上的下一个(关系)
};

extern struct node* create_list(); // 创建一个新链表,返回链表的首地址
extern struct node* insert_node_order(struct node* h, ElemType d); // 有序插入
extern struct node* create_sort_list(); // 创建一个有序新链表,返回链表的首地址
extern void print_list(struct node* h); // 遍历遍历
/*
add_a_node:在链表h中值为x的结点前面,增加一个结点
    该结点的值为a,然后返回链表的首地址。
    假设没有值为x的结点,则在尾部增加。如果有多个值为x
    的结点则增加在第一个值为x的结点前面。
*/
extern struct node* add_a_node(struct node *h, ElemType x, ElemType a);
extern struct node* delete_node(struct node *h, ElemType x); // 在h指向的链表中,删除值为x的结点
extern void update_node(struct node *h, ElemType x, ElemType a); // 把链表中值为x的结点的值改成a
extern struct node* destroy_list(struct node *h); // 销毁链表
extern struct node* reverse_list(struct node *h); // 逆置单链表
extern int get_count_node(struct node *h); // 获取结点的个数
extern bool GetElem(struct node *h, int pos, ElemType *val); // 得到第i个元素的值
extern bool ListEmpty(struct node *h); // 判断链表是否为空
extern struct node* sort_list_with_no_head(struct node *h); // 对单链表进行排序
extern struct node* LocateElem1(struct node *h, ElemType e); // 按值查找,返回地址
extern int LocateElem2(struct node *h, ElemType e); // 按值查找,返回位置序号 
extern struct node* insert_node(struct node *h, int i, ElemType e); // 插入——在第i个结点前插入一个值为e的新结点
extern struct node* delete_a_node(struct node *h, int i, ElemType *e); // 删除第i个结点

#endif

LinkedList.c

#include "LinkedList.h"

/*
    create_list:创建一个新链表,返回链表的首地址
*/
struct node* create_list() {
    ElemType d;
    struct node *head = NULL; // 指向链表的首结点
    struct node *tail = NULL; // 指向链表的尾结点
    struct node *pnew = NULL; // 指向新创建的结点
    while (1) {
        // step1:每保存一个数据,就要创建一个结点(结构体)
        scanf("%d", &d);
        if (d == 0) {
            break;
        }
        pnew = malloc(sizeof(*pnew));
        // step2:把数据写入到结点中去
        pnew->data = d;
        pnew->next = NULL;
        // step3:把结点加入到链表中
        if (head == NULL) { // 从无到有,首尾结点都是pnew
            head = pnew;
            tail = pnew;
        } else { // 从少到多
            // 尾插
            #if 1
            tail->next = pnew; // tail指向新结点
            tail = pnew; // tail被pnew替代
            #endif
            #if 0
            // 头插
            pnew->next = head; // 新结点指向head
            head = pnew; // head被pnew替代
            #endif
        }
    }
    return head;
}

// 有序插入
struct node* insert_node_order(struct node *h, ElemType d) {
    // 创建一个新节点
    struct node *pnew = (struct node*)malloc(sizeof(*pnew));
    pnew->data = d;
    pnew->next = NULL;
    // 插入
    /*
        比第一个节点要小,头插法
        比最后一个结点要大 尾插法
        中间插,找第一个比它大的结点
    */
    if (h == NULL) {
        h = pnew;
    } else {
        struct node *p = h; // 遍历结点
        struct node *pre = NULL;
        // 找第一个比pnew大的结点
        while (p) {
            if (p->data > pnew->data) {
                break;
            }
            pre = p;
            p = p->next;
        }
        if (p == NULL) { // 没有找到比它大 尾插
            pre->next = pnew;
        } else if (p == h) { // 找到的结点为第一个结点
            // 头插
            pnew->next = h;
            h = pnew;
        } else {
            // 中间插
            pnew->next = p;
            pre->next = pnew;
        }
    }
    return h;
}

/*
    create_sort_list:创建一个有序新链表,返回链表的首地址
*/
struct node* create_sort_list() {
    ElemType d;
    struct node *head = NULL; // 指向链表的首结点
    struct node *tail = NULL; // 指向链表的尾结点
    struct node *pnew = NULL; // 指向新创建的结点
    while (1) {
        // step1:每保存一个数据,就要创建一个结点(结构体)
        scanf("%d", &d);
        if (d == 0) {
            break;
        }
        pnew = malloc(sizeof(*pnew));
        // step2:把数据写入到结点中去
        pnew->data = d;
        pnew->next = NULL;
        // step3:把结点加入到链表中
        if (head == NULL) { // 从无到有,首尾结点都是pnew
            head = pnew;
            tail = pnew;
        } else { // 从少到多
            struct node *p = head; // 指向链表的首结点,作用找到第一个比新结点大的那个结点
            struct node *pre = NULL; // 指向p指向的结点的前一个结点
            while (p) { // <==> p != NULL  遍历链表
                if (p->data > pnew->data) { // 找位置
                    break;
                } else { // 本结点不是,往后走
                    pre = p;
                    p = p->next;
                }
            }
            if (p != NULL) { // 找到了一个比pnew大的结点
                if (p == head) { // 头插
                    pnew->next = head;
                    head = pnew;
                } else { // 中间插
                    pre->next = pnew;
                    pnew->next = p;
                }
            } else { // 没找到 尾插
                pre->next = pnew;
            }
        }
    }
    return head;
}

// 遍历遍历
void print_list(struct node *h) {
    // 特殊情况
    if (h == NULL) {
        return ;
    }
    while (h) {
        printf("%d ", h->data);
        h = h->next;
    }
    putchar('\n');
}

/*
add_a_node:在链表h中值为x的结点前面,增加一个结点
    该结点的值为a,然后返回链表的首地址。
    假设没有值为x的结点,则在尾部增加。如果有多个值为x
    的结点则增加在第一个值为x的结点前面。
*/
struct node* add_a_node(struct node *h, ElemType x, ElemType a) {
    // step1:创建一个值为a的新结点
    struct node *pnew = malloc(sizeof(*pnew));
    pnew->data = a;
    pnew->next = NULL;
    // 特殊情况
    if (h == NULL) {
        h = pnew;
        return h;
    }
    struct node *p = h; // 遍历指针
    struct node *pre = NULL; // 指向p指向的结点的前一个结点
    // step2:找到值为x的结点
    while (p) { // while (p != NULL)
        if (p->data == x) { // 找到了
            break;
        }
        pre = p;
        p = p->next; // 没找到,往后走
    }
    // step3:把新结点加入链表中
    if (p != NULL) { // 找到了
        if (p == h) { //头插
            pnew->next = h;
            h = pnew;
        } else { // 中间插
            // pnew->next = p; // 新结点指向p指向的结点
            // pre->next = pnew; // p指向的结点的前一个结点 指向 新结点
            pre->next = pnew;
            pnew->next = p;
        }
    } else { // 没找到
        pre->next = pnew; // 尾插
    }
    return h;
}

/*
    delete_node:在h指向的链表中,删除值为x的结点
*/
struct node* delete_node(struct node *h, ElemType x) {
    // 特殊情况
    if (h == NULL) {
        return h;
    }
    struct node *p = h; // 遍历指针
    struct node *pre = NULL; // 指向p指向的结点的前一个结点
    // step1:找到值为x的结点
    while (p) {
        if (p->data == x) { // 找到了
            // step2:删除值为x的结点
            if (p == h) { // 删除首结点
                h = h->next;
                p->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
                free(p);
                p = h;
            } else { // 删中间、末尾的结点
                pre->next = p->next;
                p->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
                free(p);
                p = pre->next; // p往后走,pre不动
            }
        } else { // 没找到 往后走
            pre = p;
            p = p->next;
        }
    }
    return h;
}

/*
    update_node:把链表中值为x的结点的值改成a
*/
void update_node(struct node *h, ElemType x, ElemType a) {
    while (h) {
        if (h->data == x) {
            h->data = a;
        }
        h = h->next; 
    }
}

/*
    销毁链表
*/
struct node* destroy_list(struct node *h) {
    if (h == NULL) {
        return h;
    }
	struct node *pc = h; // 指向被拆结点
	while (pc) {
        h = h->next;
        pc->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
        free(pc);
        pc = h;
	}
	return h;	
}

/*
    逆置单链表(不能进行额外的申请结点)
    1. 直接交换数据域
    2. 把原链表的每一个结点 摘下来,然后按照 头插法 插入到新的链表
*/
struct node* reverse_list(struct node *h) {
	struct node *head = NULL; // 保存新链表的首结点
	struct node *pc = h; // 指向被拆结点
	while (pc) {
		// 1.把原链表的每一个结点摘下来
		h = h->next;
		pc->next = NULL;
		// 2.把摘下来的结点 按照头插法 插入
		if (head == NULL) { // 从无到有
            head = pc;
        } else { // 头插
			pc->next = head;
			head = pc;
		}
		pc = h; // 再摘一个
	}
	return head;
}

/*
    获取结点的个数
    1. 递归
    2. 遍历
*/
int get_count_node(struct node *h) {
	if (h == NULL) {
        return 0;
    }
	return 1 + get_count_node(h->next);
}

// 得到第pos个元素的值
bool GetElem(struct node *h, int pos, ElemType *val) {
    if (h == NULL) {
        return false;
    }
    struct node *p = h; // 遍历指针
    int i = 1;
    while (p) {
        if (i == pos) {
            *val = p->data;     
            return true;
        }
        i++;
        p = p->next;
    }
    return false;
}

// 判断链表是否为空
bool ListEmpty(struct node *h) {
    if (h == NULL) {
        return true;
    }
   return false;
}

// 对单链表进行排序
struct node* sort_list_with_no_head(struct node *h) {
    // 1.遍历,将原来链表中的每一个结点依次摘下来
    struct node *head = h; // 指向数据结点的第一个结点
    struct node *pc = head; // 要摘下来的结点
    h = NULL;
    // 2.将摘下来的结点 插入到新的链表中
    while (pc) {
        // 摘
        head = head->next;
        pc->next = NULL;
        // 加到链表
        if (h == NULL) { // 从无到有
            h = pc;
        } else {
            // 找第一个比插入结点大的结点p
            struct node *p = h; // 遍历指针
            struct node *pre = NULL; // 指向p指向的那个结点的前一个结点
            while (p) {
                if (p->data > pc->data) {
                    break;
                }
                pre = p;
                p = p->next;
            }
            if (p == NULL) { // 没有找到 尾插
                pre->next = pc;
            } else { // 找到了
                if (p == h) { // 头插法
                    pc->next = h;
                    h = pc;
                } else { // 中间插
                    pre->next = pc;
                    pc->next = p;
                }
            }
        }
        pc = head; // 链表的第一个结点就会成为下一个要摘的结点
    }
    return h;
}

/*
按值查找,返回地址
    在链表L中查找值为e的数据元素
    找到,则返回L中值为e的数据元素的地址,查找失败返回NULL
*/
struct node* LocateElem1(struct node *h, ElemType e) {
    struct node *p = h; // 遍历指针
    while (p && p->data != e) {
        p = p->next;
    }
    return p;
}

/*
按值查找,返回位置序号  
    在链表L中查找第一个值为e的数据元素
    找到,则返回L中值为e的位置序号,查找失败返回0
*/
int LocateElem2(struct node *h, ElemType e) {
    struct node *p = h; // 遍历指针
    int j = 1;
    while (p && p->data != e) {
        p = p->next;
        j++;
    }
    if (p) {
        return j;
    }
    return 0;
}

// 插入——在第i个结点前插入一个值为e的新结点
struct node* insert_node(struct node *h, int i, ElemType e) {
    // 特殊情况
    if (h == NULL || i < 1 || i > get_count_node(h)) {
        return h;
    }
    struct node *pnew = malloc(sizeof(*pnew)); // 创建一个新结点
    pnew->data = e;
    pnew->next = NULL;

    struct node *p = h; // 遍历指针
    struct node *pre = NULL; // 遍历指针的前驱结点
    int j = 1;
    while (j != i) {
        pre = p;
        p = p->next;
        j++;
    }
    if (j == 1) { // 头插
        pnew->next = p;
        h = p;
    } else { // 中间插
        pre->next = pnew;
        pnew->next = p;
    }
    return h;
}

// 删除第i个结点
struct node* delete_a_node(struct node *h, int i, ElemType *e) {
    // 特殊情况
    if (h == NULL || i < 1 || i > get_count_node(h)) {
        return h;
    }
    struct node *p = h; // 遍历指针
    struct node *pre = NULL; // 遍历指针的前驱结点
    int j = 1;
    while (j != i) {
        pre = p;
        p = p->next;
        j++;
    }
    if (j == 1) { // 头删
        *e = p->data; // 保存被删除结点数据
        h = h->next;
        p->next = NULL;
        free(p);
    } else { // 中间删、尾删
        *e = p->data;
        pre->next = p->next;
        p->next = NULL;
        free(p);
    }
    return h;
}

main.c

#include "LinkedList.h"

int main(int argc, char *argv[]) {
    // struct node *h = create_list(); // 创建一个新链表,返回链表的首地址
    struct node *h = create_sort_list(); // 创建一个有序新链表,返回链表的首地址
    print_list(h); // 遍历遍历
    printf("链表长度为:%d\n", get_count_node(h));

    h = add_a_node(h, 3, 999); // 在值为3的结点前面增加一个值为999的结点
    print_list(h); // 遍历遍历
    printf("链表长度为:%d\n", get_count_node(h));

    h = delete_node(h, 999); // 删除值为999的结点
    print_list(h); // 遍历遍历
    printf("链表长度为:%d\n", get_count_node(h));

    update_node(h, 3, 33); // 把链表中值为3的结点的值改成33
    print_list(h); // 遍历遍历
    printf("链表长度为:%d\n", get_count_node(h));

    h = reverse_list(h); // 逆置单链表
    print_list(h); // 遍历遍历
    printf("链表长度为:%d\n", get_count_node(h));

    ElemType d;
    if (GetElem(h, 2, &d)) { // 得到第二个元素的值
        printf("第二个元素的值为:%d\n", d);
    }

    h = sort_list_with_no_head(h); // 对单链表进行排序
    print_list(h); // 遍历遍历
    printf("链表长度为:%d\n", get_count_node(h));

    h = insert_node_order(h, 99); //有序插入99
    print_list(h); // 遍历遍历
    printf("链表长度为:%d\n", get_count_node(h));

    if (LocateElem1(h, 33)) { // 按值查找,返回地址
        printf("%d的地址: %p\n", 33, LocateElem1(h, 33));
    }

    if (LocateElem2(h, 33)) { // 按值查找,返回位置序号
        printf("%d的序号: %d\n", 33, LocateElem2(h, 33));
    }

    insert_node(h, 2, 111); // 插入——在第2个结点前插入一个新结点
    print_list(h); // 遍历遍历
    printf("链表长度为:%d\n", get_count_node(h));

    while (!ListEmpty(h)) {
        h = delete_a_node(h, 1, &d);
        printf("第1个结点: %d被删除\n", d);
        print_list(h);
        printf("链表长度为:%d\n", get_count_node(h));
    }

    h = destroy_list(h); // 销毁链表

    return 0;
}

带头结点单链表

LinkedListWithHead.h

#ifndef __LINKEDLISTWITHHEAD_H__
#define __LINKEDLISTWITHHEAD_H__

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

typedef int ElemType;

struct node {
    ElemType data; //数据域  保存数据
    struct node *next; //指针域 保存逻辑上的下一个(关系)
};

// 头结点的数据类型 保存链表的属性
struct list {
    struct node *first; // 指向第一个数据结点
    struct node *last; // 指向最后一个数据结点
    int NodeNum; // 记录链表的长度
    /*
        其他属性
    */
};

struct list* create_list(); // 创建一个新链表,返回链表的首地址
void insert_node_order(struct list *list, ElemType d); // 有序插入
struct list* create_sort_list(); // 创建一个有序新链表,返回链表的首地址
void print_list(struct list *list); // 遍历遍历
struct list* clear_list(struct list *list); // 清空链表
/*
add_a_node:在链表h中值为x的结点前面,增加一个结点
    该结点的值为a,然后返回链表的首地址。
    假设没有值为x的结点,则在尾部增加。如果有多个值为x
    的结点则增加在第一个值为x的结点前面。
*/
struct list* add_a_node(struct list *list, ElemType x, ElemType a);
struct list* delete_node(struct list *list, ElemType x); // 在h指向的链表中,删除值为x的结点
void update_node(struct list *list, ElemType x, ElemType a); // 把链表中值为x的结点的值改成a
struct list* destroy_list(struct list *list); // 销毁带头结点的单链表
void sort_list_with_head(struct list *list); // 对带头结点的单链表进行排序
void reverse_list(struct list *list); // 逆置链表
bool GetElem(struct list *list, int pos, ElemType *val); // 得到第i个元素的值
bool ListEmpty(struct list *list); // 判断链表是否为空
struct node* LocateElem1(struct list *list, ElemType e); // 按值查找,返回地址
int LocateElem2(struct list *list, ElemType e); // 按值查找,返回位置序号
bool insert_node(struct list *list, int i, ElemType e); // 插入——在第i个结点前插入一个值为e的新结点
bool delete_a_node(struct list *list, int i, ElemType *e); // 删除第i个结点

#endif

LinkedListWithHead.c

#include "LinkedListWithHead.h"

/*
    create_list:创建一个新链表,返回链表的首地址
*/
struct list* create_list() {
    ElemType d;
    struct node *pnew = NULL; // 指向新创建的结点

    // step0:创建一个头结点并初始化
    struct list *list = malloc(sizeof(*list));
    list->first = NULL; // 指向第一个数据结点
    list->last = NULL; // 指向最后一个数据结点
    list->NodeNum = 0; // 链表长度
    while (1) {
        // step1:每保存一个数据,就要创建一个结点(结构体)
        scanf("%d", &d);
        if (d == 0) {
            break;
        }
        pnew = malloc(sizeof(*pnew));
        list->NodeNum++; // 每创建一个新数据结点,属性NodeNum就加一
        // step2:把数据写入到结点中去
        pnew->data = d;
        pnew->next = NULL;
        // step3:把结点加入到链表中
        if (list->first == NULL) { // 从无到有,首尾结点都是pnew
            list->first = pnew;
            list->last = pnew;
        } else { // 从少到多
            // 尾插
            #if 1
            list->last->next = pnew; // list->last 指向新结点
            list->last = pnew; // list->last被pnew替代
            #endif
            #if 0
            // 头插
            pnew->next = list->first; // 新结点指向list->first
            list->first = pnew; // list->first被pnew替代
            #endif
        }
    }
    return list;
}

// 有序插入
void insert_node_order(struct list *list, ElemType d) {
    if (list == NULL) {
        return ;
    }
    // 创建一个新节点
    struct node *pnew = (struct node*)malloc(sizeof(*pnew));
    pnew->data = d;
    pnew->next = NULL;
    // 插入
    /*
        比第一个节点要小,头插法
        比最后一个结点要大 尾插法
        中间插,找第一个比它大的结点
    */
    if (list->first == NULL) { //从无到有
        list->first = list->last = pnew;
    } else {
        struct node *p = list->first; // 遍历指针
        struct node *pre = NULL; // 指向遍历指针的前驱结点
        while (p) { // 找第一个比pnew大的结点
            if (p->data > pnew->data) {
                break;
            }   
            pre = p;
            p = p->next;
        }
        if (p == NULL) { // 没有找到比它大 尾插
            list->last->next = pnew;
            list->last = pnew;
        } else { // 找到了
            if (p == list->first) { // 找到的结点为第一个结点
                // 头插
                pnew->next = list->first;
                list->first = pnew;
            } else {
                // 中间插
                pre->next = pnew;
                pnew->next = p;
            }
        }
    }
    list->NodeNum++;
}

/*
    create_sort_list:创建一个有序新链表,返回链表的首地址
*/
struct list* create_sort_list() {
    ElemType d;
    struct node *pnew = NULL; // 指向新创建的结点

    // step0:创建一个头结点并初始化
    struct list *list = malloc(sizeof(*list));
    list->first = NULL; // 指向第一个数据结点
    list->last = NULL; // 指向最后一个数据结点
    list->NodeNum = 0; // 链表长度
    while (1) {
        // step1:每保存一个数据,就要创建一个结点(结构体)
        scanf("%d", &d);
        if (d == 0) {
            break;
        }
        pnew = malloc(sizeof(*pnew));
        list->NodeNum++; // 每加入一个新结点,链表长度属性+1
        // step2:把数据写入到结点中去
        pnew->data = d;
        pnew->next = NULL;
        // step3:把结点加入到链表中
        if (list->first == NULL) { // 从无到有
            list->first = pnew;
            list->last = pnew;
        } else { // 从少到多
            struct node *p = list->first; // 指向链表的第一个数据结点,作用找到第一个比新结点大的那个结点
            struct node *pre = NULL; // 指向p指向的结点的前一个结点
            while (p) { // <==> p != NULL  遍历链表
                if (p->data > pnew->data) { // 找位置
                    break;
                } else { // 本结点不是,往后走
                    pre = p;
                    p = p->next;
                }
            }
            if (p != NULL) { // 找到了一个比pnew大的结点
                if (p == list->first) { // 头插
                    pnew->next = list->first;
                    list->first = pnew;
                } else { // 中间插
                    pre->next = pnew;
                    pnew->next = p;
                }
            } else { // 没找到 尾插
                pre->next = pnew;
                list->last = pnew; // 更新头结点的last属性 
            }
        }
    }
    return list;
}

// 遍历遍历
void print_list(struct list *list) {
    if (list == NULL || list->NodeNum == 0) {
        return ;
    } 
    struct node *p = list->first; // 遍历指针
    while (p) {
        printf("%d ", p->data);
        p = p->next;
    }
    putchar('\n');
}

// 清空链表
struct list* clear_list(struct list *list) {
    if (list == NULL || list->NodeNum == 0) {
        return list;
    }
    struct node *p = list->first; // 遍历指针
    struct node *pc = NULL; // 指向被拆结点
    while (p) { // 头删
        pc = p;
        p = p->next;
        pc->next = NULL;
        free(pc);
    }
    list->first = NULL;
    list->last = NULL;
    list->NodeNum = 0;
    return list; 
}

/*
add_a_node:在链表h中值为x的结点前面,增加一个结点
    该结点的值为a,然后返回链表的首地址。
    假设没有值为x的结点,则在尾部增加。如果有多个值为x
    的结点则增加在第一个值为x的结点前面。
*/
struct list* add_a_node(struct list *list, ElemType x, ElemType a) {
    // 特殊情况
    if (list == NULL) {
        return NULL;
    }
    // step1:创建一个值为a的新结点
    struct node *pnew = malloc(sizeof(*pnew));
    pnew->data = a;
    pnew->next = NULL;

    if (list->first == NULL) { // 从无到有
        list->first = list->last = pnew;
    } else {
        struct node *p = list->first; // 遍历指针
        struct node *pre = NULL; // 指向p指向的结点的前一个结点
        // step2:找到值为x的结点
        while (p) { // while (p != NULL)
            if (p->data == x) { // 找到了
                break;
            }
            // 没找到,往后走
            pre = p;
            p = p->next;
        }
        // step3:把新结点加入链表中
        if (p != NULL) { // 找到了
            if (p == list->first) { // 头插
                pnew->next = list->first; // 新结点指向原链表的第一个数据结点
                list->first = pnew; // 更新头结点的first属性
            } else { // 中间插
                // pnew->next = p; // 新结点指向p指向的结点
                // pre->next = pnew; // p指向的结点的前一个结点 指向 新结点
                pre->next = pnew;
                pnew->next = p;
            }
        } else { // 没找到
            pre->next = pnew; // 尾插
            list->last = pnew; // 更新头结点的属性last
        }
    }
    list->NodeNum++; // 更新链表的长度
    return list;
}

/*
    delete_node:在h指向的链表中,删除值为x的结点
*/
struct list* delete_node(struct list *list, ElemType x) {
    // 特殊情况
    if (list == NULL || list->first == NULL) {
        return NULL;
    }
    struct node *p = list->first; // 遍历指针
    struct node *pre = NULL; // 指向p指向的结点的前一个结点
    // step1:找到值为x的结点
    while (p) {
        if (p->data == x) { // 找到了
            list->NodeNum--;
            // step2:删除值为x的结点
            if (p == list->first) { // 删除第一个数据结点
                list->first = list->first->next;
                p->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
                free(p);
                p = list->first;
                if (list->NodeNum == 0) { // 当删除到没有数据结点时
                    list->last = NULL;
                }
            } else if (p == list->last) { // 删除最后一个数据结点
                list->last = pre;
                list->last->next = NULL;
                p->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
                free(p);
            } else { // 删中间
                pre->next = p->next;
                p->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
                free(p);
                p = pre->next; // p往后走,pre不动
            }
        } else { // 没找到 往后走
            pre = p;
            p = p->next;
        }
    }
    return list;
}

/*
    update_node:把链表中值为x的结点的值改成a
*/
void update_node(struct list *list, ElemType x, ElemType a) {
    struct node *p = list->first; // 遍历指针
    while (p) {
        if (p->data == x) {
            p->data = a;
        }
        p = p->next;
    }
}

// 销毁带头结点的单链表
struct list* destroy_list(struct list *list) {
    if (list == NULL) {
        return list;
    }
    struct node *p = list->first; // 遍历指针
    struct node *pc = NULL; // 指向要拆的那个数据结点
    // 拆并释放数据结点
    while (p) { // 头删
        pc = p;
        p = p->next;
        pc->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
        free(pc);
    }
    list->first = NULL;
    list->last = NULL;
    free(list); // 释放头结点
    list = NULL;
    return list;
}

// 对带头结点的单链表进行排序
void sort_list_with_head(struct list *list) {
    if (list == NULL || list->NodeNum == 0 || list->NodeNum == 1) {
        return ;
    }
    // 1.遍历,将原来链表中的每一个结点依次摘下来
    struct node *head = list->first; // 遍历指针
    struct node *pc = NULL; // 要摘下来的结点

    list->first = NULL;
    list->last = NULL;

    // 2.将摘下来的结点 插入到新的链表中
    while (head) {
        // 摘
        pc = head;
        head = head->next;
        pc->next = NULL;
        // 加到链表
        if (list->first == NULL) { // 从无到有
            list->first = list->last = pc;
        } else {
            // 找第一个比插入结点大的结点p
            struct node *p = list->first; // 遍历指针
            struct node *pre = NULL; // 指向p指向的结点的前一个结点
            while (p) {
                if (p->data > pc->data) {
                    break;
                }   
                pre = p;
                p = p->next;
            }
            if (p == NULL) { // 没有找到 尾插
                list->last->next = pc;
                list->last = pc;
            } else { // 找到了
                if (p == list->first) { // 头插法
                    pc->next = list->first;
                    list->first = pc;
                } else { // 中间插
                    pre->next = pc;
                    pc->next = p;
                }
            }
        }
    }
}

/*
逆置单链表(不能进行额外的申请结点)
    1.(直接交换数据域)
    2.(把原链表的每一个结点 摘下来,然后按照 头插法 插入到新的链表)
*/
void reverse_list(struct list *list) {
    if (list == NULL || list->NodeNum == 0 || list->NodeNum == 1) {
        return ;
    }
	struct node *head = list->first; // 遍历指针
	struct node *pc = NULL; // 指向被拆结点

    list->first = NULL;
    list->last = NULL;

	while (head) {
		// 1.把原链表的每一个结点摘下来
        pc = head;
		head = head->next;
		pc->next = NULL;
		// 2.把摘下来的结点 按照头插法 插入
		if (list->first == NULL) { // 从无到有
            list->first = list->last = pc;
        } else { // 头插
			pc->next = list->first;
			list->first = pc;
		}
	}
}

// 得到第i个元素的值
bool GetElem(struct list *list, int pos, ElemType *val) {
    // 特殊情况
    if (list == NULL || list->NodeNum == 0 || pos < 1 || pos > list->NodeNum) {
        return false;
    }
    struct node *p = list->first; // 遍历指针
    int i = 1;
    while (p) {
        if (i == pos) {
            *val = p->data;     
            return true;
        }
        i++;
        p = p->next;
    }
    return false;
}

// 判断链表是否为空
bool ListEmpty(struct list *list) {
    if (list == NULL || list->NodeNum == 0) {
        return true;
    }
    return false;
}

/*
按值查找,返回地址
    在链表L中查找值为e的数据元素
    找到,则返回L中值为e的数据元素的地址,查找失败返回NULL
*/
struct node* LocateElem1(struct list *list, ElemType e) {
    if (list == NULL) {
        return NULL;
    }
    struct node *p = list->first; // 遍历指针
    while (p && p->data != e) {
        p = p->next;
    }
    return p;
}

/*
按值查找,返回位置序号
    在链表L中查找第一个值为e的数据元素
    找到,则返回L中值为e的位置序号,查找失败返回0
*/
int LocateElem2(struct list *list, ElemType e) {
    if (list == NULL) {
        return 0;
    }
    struct node *p = list->first; // 遍历指针
    int j = 1;
    while (p && p->data != e) {
        p = p->next;
        j++;
    }
    if (p) {
        return j;
    }
    return 0;
}

// 插入——在第i个结点前插入一个值为e的新结点
bool insert_node(struct list *list, int i, ElemType e) {
    // 特殊情况
    if (list == NULL || list->NodeNum == 0 || i < 1 || i > list->NodeNum) {
        return false;
    }
    struct node *pnew = malloc(sizeof(*pnew)); // 创建一个新结点
    pnew->data = e;
    pnew->next = NULL;

    struct node *p = list->first; // 遍历指针
    struct node *pre = NULL; // 遍历指针的前驱结点
    int j = 1;
    while (j != i) {
        pre = p;
        p = p->next;
        j++;
    }
    if (p == list->first) { // 头插
        pnew->next = list->first;
        list->first = pnew;
    } else { // 中间插
        pre->next = pnew;
        pnew->next = p;
    }
    list->NodeNum++; // 链表长度+1
    return true;
}

// 删除第i个结点
bool delete_a_node(struct list *list, int i, ElemType *e) {
    // 特殊情况
    if (list == NULL || list->NodeNum == 0 || i < 1 || i > list->NodeNum) {
        return false;
    }
    struct node *p = list->first; // 遍历指针
    struct node *pre = NULL; // 遍历指针的前驱结点
    int j = 1;
    while (j != i) {
        pre = p;
        p = p->next;
        j++;
    }
    list->NodeNum--; // 链表长度减一
    if (p == list->first) { // 头删
        *e = p->data; // 保存被删结点数据
        list->first = list->first->next;
        p->next = NULL;
        free(p);
        if (list->NodeNum == 0) { // 当删除到没有数据结点时
            list->last = NULL;
        }
    } else if (p == list->last) { // 尾删
        list->last = pre;
        list->last->next = NULL;
        *e = p->data; // 保存被删结点数据
        free(p);
    } else { // 中间删
        *e = p->data;
        pre->next = p->next;
        p->next = NULL;
        free(p);
    }
    return true;
}

main.c

#include "LinkedListWithHead.h"

int main(int argc, char *argv[]) {
    // struct list *list = create_list(); // 创建一个新链表,返回链表的首地址
    struct list *list = create_sort_list(); // 创建一个有序新链表,返回链表的首地址
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    list = add_a_node(list, 3, 999); // 在值为3的结点前面增加一个值为999的结点
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    list = delete_node(list, 999); // 删除值为999的结点
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    update_node(list, 3, 33); // 把链表中值为3的结点的值改成33
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    reverse_list(list); // 逆置链表
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    ElemType d;
    if (GetElem(list, 2, &d)) { // 得到第二个元素的值
        printf("第二个元素的值为:%d\n", d);
    }

    sort_list_with_head(list); //对链表进行排序
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    insert_node_order(list, 99); //有序插入99
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    if (LocateElem1(list, 33)) { // 按值查找,返回地址
        printf("%d的地址: %p\n", 33, LocateElem1(list, 33));
    }

    if (LocateElem2(list, 33)) { // 按值查找,返回位置序号
        printf("%d的序号: %d\n", 33, LocateElem2(list, 33));
    }
        
    if (insert_node(list, list->NodeNum, 111)) { // 插入——在第2个结点前插入一个新结点
        print_list(list); // 遍历遍历
        printf("链表长度为:%d\n", list->NodeNum);
    }
        
    while (!ListEmpty(list)) {
        if (delete_a_node(list, 1, &d)) {
            printf("第1个结点: %d被删除\n", d);
            print_list(list);
            printf("链表长度为:%d\n", list->NodeNum);
        }
    }
    
    list = destroy_list(list); // 销毁链表

    return 0;
}

带头结点双链表

BothWithLinkedListWithHead.h

#ifndef __BOTHWITHLINKEDLISTWITHHEAD_H__
#define __BOTHWITHLINKEDLISTWITHHEAD_H__

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

typedef int ElemType;

// 数据结点
struct node {
    ElemType data; // 数据域 存储数据
    struct node *next; // 指针域 保存逻辑上的下一个(关系)
    struct node *prev; // 指针域 保存逻辑上的上一个(关系)
};

// 头结点的数据类型 保存链表的属性
struct list {
    struct node *first; // 指向第一个数据结点
    struct node *last; // 指向最后一个数据结点
    int NodeNum; // 记录链表的长度
    /*
        其他属性
    */
};

extern struct list* create_list();
extern void insert_node_order(struct list *list, ElemType d);
extern struct list* create_sort_list();
extern void print_list(struct list *list);
extern struct list* clear_list(struct list *list);
extern struct list* clear_list(struct list *list);
extern struct list* add_a_node(struct list *list, ElemType x, ElemType a);
extern struct list* delete_node(struct list *list, ElemType x);
extern void update_node(struct list *list, ElemType x, ElemType a);
extern struct list* destroy_list(struct list *list);
extern void sort_list_with_head(struct list *list);
extern void reverse_list(struct list *list);
extern bool GetElem(struct list *list, int pos, ElemType *val);
extern bool ListEmpty(struct list *list);
extern struct node* LocateElem1(struct list *list, ElemType e);
extern int LocateElem2(struct list *list, ElemType e);
extern bool insert_node(struct list *list, int i, ElemType e);
extern bool delete_a_node(struct list *list, int i, ElemType *e);

#endif

BothWithLinkedListWithHead.c

#include "BothWithLinkedListWithHead.h"

/*
    create_list:创建一个新链表,返回链表的首地址
*/
struct list* create_list() {
    ElemType d;
    struct node *pnew = NULL; // 指向新创建的结点
    // step0:创建一个头结点并初始化
    struct list *list = malloc(sizeof(*list));
    list->first = NULL; // 指向第一个数据结点
    list->last = NULL; // 指向最后一个数据结点
    list->NodeNum = 0; // 链表长度
    while (1) {
        // step1:每保存一个数据,就要创建一个结点(结构体)
        scanf("%d", &d);
        if (d == 0) {
            break;
        }
        pnew = malloc(sizeof(*pnew));
        list->NodeNum++; // 每创建一个新数据结点,属性NodeNum就加一
        // step2:把数据写入到结点中去
        pnew->data = d;
        pnew->next = NULL;
        pnew->prev = NULL;
        // step3:把结点加入到链表中
        if (list->first == NULL) { // 从无到有,首尾结点都是pnew
            list->first = pnew;
            list->last = pnew;
        } else { // 从少到多
            // 尾插
            #if 1
            list->last->next = pnew; // list->last 指向新结点
            pnew->prev = list->last;
            list->last = pnew; // list->last被pnew替代
            #endif
            #if 0
            // 头插
            pnew->next = list->first; // 新结点指向list->first
            list->first->prev = pnew;
            list->first = pnew; // list->first被pnew替代
            #endif
        }
    }
    return list;
}

// 有序插入
void insert_node_order(struct list *list, ElemType d) {
    if (list == NULL) {
        return ;
    }
    // 创建一个新节点
    struct node *pnew = (struct node*)malloc(sizeof(*pnew));
    pnew->data = d;
    pnew->next = NULL;
    pnew->prev = NULL;
    // 插入
    /*
        比第一个节点要小,头插法
        比最后一个结点要大 尾插法
        中间插,找第一个比它大的结点
    */
    if (list->first == NULL) { // 从无到有
        list->first = list->last = pnew;
    } else {
        struct node *p = list->first; // 遍历指针
        while (p) { // 找第一个比pnew大的结点
            if (p->data > pnew->data) {
                break;
            } 
            p = p->next;
        }
        if (p == NULL) { // 没有找到比它大 尾插
            list->last->next = pnew;
            pnew->prev = list->last;
            list->last = pnew;
        } else {
            if (p == list->first) { // 找到的结点为第一个结点
                // 头插
                pnew->next = list->first;
                list->first->prev = pnew;
                list->first = pnew;
            } else {
                // 中间插
                pnew->next = p;
                pnew->prev = p->prev;
                p->prev->next = pnew;
                p->prev = pnew;
            }
        }
    }
    list->NodeNum++;
}

/*
    create_sort_list:创建一个有序新链表,返回链表的首地址
*/
struct list* create_sort_list() {
    ElemType d;
    struct node *pnew = NULL; // 指向新创建的结点
    // step0:创建一个头结点并初始化
    struct list *list = malloc(sizeof(*list));
    list->first = NULL; // 指向第一个数据结点
    list->last = NULL; // 指向最后一个数据结点
    list->NodeNum = 0; // 链表长度
    while (1) {
        // step1:每保存一个数据,就要创建一个结点(结构体)
        scanf("%d", &d);
        if (d == 0) {
            break;
        }
        pnew = malloc(sizeof(*pnew));
        list->NodeNum++;
        // step2:把数据写入到结点中去
        pnew->data = d;
        pnew->next = NULL;
        pnew->prev = NULL;
        // step3:把结点加入到链表中
        if (list->first == NULL) { // 数据结点从无到有
            list->first = pnew;
            list->last = pnew;
        } else { // 从少到多
            struct node *p = list->first; // 指向链表的第一个数据结点,找第一个比新结点大的那个结点
            while (p) { // <==> p != NULL  遍历链表
                if (p->data > pnew->data) { // 找位置
                    break;
                } else { //本结点不是,往后走
                    p = p->next;
                }
            }
            if (p != NULL) { // 找到有第一个比pnew大的结点
                if (p == list->first) { // 头插
                    pnew->next = list->first;
                    list->first->prev = pnew;
                    list->first = pnew;
                } else { // 中间插
                    pnew->next = p;
                    pnew->prev = p->prev;
                    p->prev->next = pnew;
                    p->prev = pnew;
                }
            } else { // 没找到 尾插
               list->last->next = pnew;
               pnew->prev = list->last;
               list->last = pnew; // 更新头结点的last属性
            }
        }
    }
    return list;
}

// 遍历遍历
void print_list(struct list *list) {
    // 异常处理
    if (list == NULL || list->NodeNum == 0) {
        return ;
    }
    struct node *p = list->first; // 遍历指针
    while (p) {
        printf("%d ", p->data);
        p = p->next;
    }
    putchar('\n');
}

// 清空链表
struct list* clear_list(struct list* list) {
    if (list == NULL || list->NodeNum == 0) {
        return list;
    }
    struct node *p = list->first; // 遍历指针
    struct node *pc = NULL; // 指向被拆结点
    while (p) { // 头删
        pc = p;
        p = p->next;
        if (p) {
            p->prev = NULL;
        }
        pc->next = NULL;
        free(pc);
    }
    list->first = NULL;
    list->last = NULL;
    list->NodeNum = 0;
    return list; 
}

/*
add_a_node:在链表h中值为x的结点前面,增加一个结点
    该结点的值为a,然后返回链表的首地址。
    假设没有值为x的结点,则在尾部增加。如果有多个值为x
    的结点则增加在第一个值为x的结点前面。
*/
struct list* add_a_node(struct list* list, ElemType x, ElemType a) {
    // 异常处理
    if (list == NULL) {
        return NULL;
    }
    // step1:创建一个值为a的新结点
    struct node *pnew = malloc(sizeof(*pnew));
    pnew->data = a;
    pnew->next = NULL;
    pnew->prev = NULL;
    if (list->first == NULL) { // 从无到有
        list->first = list->last = pnew;
    } else {
        // step2:找到值为x的结点
        struct node *p = list->first; // 遍历指针
        while (p) { // while (p != NULL)
            if (p->data == x) { // 找到了
                break;
            }
            p = p->next; // 没找到,往后走
        }
        // step3:把新结点加入链表中
        if (p != NULL) { // 找到了
            if (p == list->first) { // 头插
                pnew->next = list->first; // 新结点指向原链表的第一个数据结点
                list->first->prev = pnew; 
                list->first=pnew; // 更新头结点的first属性
            } else { // 中间插
                pnew->next = p;
                pnew->prev = p->prev;
                p->prev->next = pnew;
                p->prev = pnew;
            }
        } else { // 没找到 尾插
            list->last->next = pnew;
            pnew->prev = list->last; 
            list->last = pnew; // 更新头结点的属性last
        }
    }
    list->NodeNum++; // 更新链表的长度
    return list;
}

/*
    delete_node:在h指向的链表中,删除值为x的结点
*/
struct list* delete_node(struct list *list, ElemType x) {
    // 异常处理
    if (list == NULL || list->first == NULL) {
        return NULL;
    }
    struct node* p = list->first; // 遍历指针
    // step1:找到值为x的结点
    while (p) {
        if (p->data == x) { // 找到了
            list->NodeNum--; // 链表长度减一
            // step2:删除值为x的结点
            if (p == list->first) { // 删除第一个数据结点
                list->first = list->first->next;
                if (list->first) {
                    list->first->prev = NULL;
                } else {
                    list->last = NULL;
                }
                p->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
                free(p);
                p = list->first; // p往后走
            } else if (p == list->last) { // 删除最后一个数据结点
                list->last = p->prev;
                list->last->next = NULL;
                p->prev = NULL;
                free(p);
            } else { // 删中间
                struct node *psave = p->next; // 用psave保存p的下一个结点  save:保存
                p->prev->next = p->next;
                p->next->prev = p->prev;
                p->prev = NULL;
                p->next = NULL;
                free(p);
                p = psave; // p往后走
            }
        } else { // 没找到 往后走
            p = p->next;
        }
    }
    return list;
}

/*
    update_node:把h指向的链表中,值为x的结点的值改成a
*/
void update_node(struct list *list, ElemType x, ElemType a) {
    struct node *p = list->first; // p是遍历指针
    while (p) {
        if (p->data == x) {
            p->data = a;
        }
        p = p->next;
    }
}

/*
    destroy_list:销毁带头双链表
*/
struct list* destroy_list(struct list *list) {
    // 异常处理
    if (list == NULL) {
        return NULL;
    }
    struct node *pc = list->first; // 指向被删结点
    while (pc) // 头删
    {
        list->first = list->first->next;
        if (list->first) {
            list->first->prev = NULL;
        }
        pc->next = NULL;
        free(pc);
        pc = list->first;
    }
    // 删除头结点
    list->last = NULL;
    free(list);
    list == NULL;
    return list;
}

// 对带头结点的双链表进行排序
void sort_list_with_head(struct list *list) {
    // 异常处理
    if (list == NULL || list->NodeNum == 0 || list->NodeNum == 1) {
        return ;
    }
    // 1.遍历,将原来链表中的每一个结点依次摘下来
    struct node *head = list->first; // 指向数据结点的第一个节点、遍历指针
    struct node *pc = NULL; // 要摘下来的结点

    list->first = NULL; 
    list->last = NULL;

    // 2.将摘下来的结点 插入到新的链表中
    while (head) {
        // 头摘
        pc = head;
        head = head->next;
        pc->next = NULL;
        pc->prev = NULL;
        // 加到链表
        if (list->first == NULL) { // 从无到有
            list->first = list->last = pc;
        } else {
            // 找第一个比插入结点大的结点p
            struct node *p = list->first; // 遍历指针
            while (p) {
                if(p->data > pc->data) {
                    break;
                }  
                p = p->next;
            }
            if (p == NULL) { // 没有找到 尾插
                list->last->next = pc;
                pc->prev = list->last;
                list->last = pc;
            } else {
                if (p == list->first) { // 头插法
                    pc->next = list->first;
                    list->first->prev = pc;
                    list->first = pc;
                } else { // 中间插
                    struct node *pre = p->prev;
                    pc->next = p;
                    pc->prev = pre;
                    pre->next = pc;
                    p->prev = pc;
                }
            }
        }
    }
}

/*
逆置双链表(不能进行额外的申请结点)
    1.(直接交换数据域)
    2.(把原链表的每一个结点 摘下来,然后按照 头插法 插入到新的链表)
*/
void reverse_list(struct list *list) {
    if (list == NULL || list->NodeNum == 0 || list->NodeNum == 1) {
        return ;
    }
	struct node *head = list->first; // 遍历指针
	struct node *pc = head; // 指向被拆结点

    list->first = NULL;
    list->last = NULL;

	while (head) {
		// 1.把原链表的每一个结点摘下来
        pc = head;
		head = head->next;
        if (head) {
            head->prev = NULL;
        }
		pc->next = NULL;
		// 2.把摘下来的结点 按照头插法 插入
		if (list->first == NULL) { // 从无到有
            list->first = list->last = pc;
        } else {
			pc->next = list->first;
            list->first->prev = pc;
			list->first = pc;
		}
	}
}

// 得到第i个元素的值
bool GetElem(struct list *list, int pos, ElemType *val) {
    if (list == NULL || list->NodeNum == 0 || pos < 1 || pos > list->NodeNum) {
        return false;
    }
    struct node *p = list->first; // 遍历指针
    int i = 1;
    while (p) {
        if (i == pos) {
            *val = p->data;     
            return true;
        }
        i++;
        p = p->next;
    }
    return false;
}

// 判断链表是否为空
bool ListEmpty(struct list *list) {
    if (list == NULL || list->NodeNum == 0) {
        return true;
    }
    return false;
}

/*
按值查找,返回地址
    在链表L中查找值为e的数据元素
    找到,则返回L中值为e的数据元素的地址,查找失败返回NULL
*/
struct node* LocateElem1(struct list *list, ElemType e) {
    if (list == NULL) {
        return NULL;
    }
    struct node *p = list->first;
    while (p && p->data != e) {
        p = p->next;
    }
    return p;
}
 
/*
按值查找,返回位置序号
    在链表L中查找第一个值为e的数据元素
    找到,则返回L中值为e的位置序号,查找失败返回0
*/
int LocateElem2(struct list *list, ElemType e) {
    if (list == NULL) {
        return 0;
    }
    struct node *p = list->first; // 遍历指针
    int j = 1;
    while (p && p->data != e) {
        p = p->next;
        j++;
    }
    if (p) {
        return j;
    }
    return 0;
}

// 插入——在第i个结点前插入一个值为e的新结点
bool insert_node(struct list *list, int i, ElemType e) {
    // 异常处理
    if (list == NULL || list->NodeNum == 0 || i < 1 || i > list->NodeNum) {
        return false;
    }
    struct node *pnew = malloc(sizeof(*pnew)); // 创建一个新结点
    pnew->data = e;
    pnew->next = NULL;
    pnew->prev = NULL;

    struct node *p = list->first; // 遍历指针
    int j = 1;
    while (j != i) {
        p = p->next;
        j++;
    }
    if (j == 1) { // 头插
        pnew->next = list->first;
        list->first->prev = pnew;
        list->first = pnew;
    } else { // 中间插
        pnew->next = p;
        pnew->prev = p->prev;
        p->prev->next = pnew;
        p->prev = pnew;
    }
    list->NodeNum++; // 链表长度加1
    return true;
}

// 删除第i个结点
bool delete_a_node(struct list *list, int i, ElemType *e) {
    // 特殊情况
    if (list == NULL || list->NodeNum == 0 || i < 1 || i > list->NodeNum) {
        return false;
    }
    struct node *p = list->first; // 遍历指针
    int j = 1;
    while (j != i) {
        p = p->next;
        j++;
    }
    list->NodeNum--; // 链表长度减一
    if (j == 1) { // 头删
        list->first = list->first->next;
        if (list->first) {
            list->first->prev = NULL;
        } else { // 链表长度 == 0
            list->last = NULL;
        }
        *e = p->data; // 保存被拆结点数据
        p->next = NULL;
        free(p);
    } else if (p == list->last) { // 尾删
        list->last = p->prev;
        list->last->next = NULL;
        *e = p->data; // 保存被拆结点数据
        p->prev = NULL;
        free(p);
    } else { // 中间删
        struct node *pre = p->prev; // 被删结点的前驱结点
        *e = p->data; // 保存被拆结点数据
        pre->next = p->next;
        p->next->prev = pre;
        p->next = NULL;
        p->prev = NULL;
        free(p);
    }
    return true;
}

main.c

#include "BothWithLinkedListWithHead.h"

int main(int argc, char *argv[]) {
    // struct list *list = create_list(); // 创建一个新链表,返回链表的首地址
    struct list *list = create_sort_list(); // 创建一个有序新链表,返回链表的首地址
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    list = add_a_node(list, 3, 999); // 在值为3的结点前面增加一个值为999的结点
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    list = delete_node(list, 999); // 删除值为999的结点
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    update_node(list, 3, 33); // 把链表中值为3的结点的值改成33
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    reverse_list(list); // 逆置链表
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    ElemType d;
    if (GetElem(list, 2, &d)) { // 得到第二个元素的值
        printf("第二个元素的值为:%d\n", d);
    }

    sort_list_with_head(list); //对链表进行排序
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    insert_node_order(list, 99); //有序插入99
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    if (LocateElem1(list, 33)) { // 按值查找,返回地址
        printf("%d的地址: %p\n", 33, LocateElem1(list, 33));
    }

    if (LocateElem2(list, 33)) { // 按值查找,返回位置序号
        printf("%d的序号: %d\n", 33, LocateElem2(list, 33));
    }
        
    if (insert_node(list, list->NodeNum, 111)) { // 插入——在第2个结点前插入一个新结点
        print_list(list); // 遍历遍历
        printf("链表长度为:%d\n", list->NodeNum);
    }
        
    while (!ListEmpty(list)) {
        if (delete_a_node(list, 1, &d)) {
            printf("第1个结点: %d被删除\n", d);
            print_list(list);
            printf("链表长度为:%d\n", list->NodeNum);
        }
    }
    
    list = destroy_list(list); // 销毁链表

    return 0;
}

带头循环单链表

CircleLinkedListWithHead.h

#ifndef __CIRCLELINKEDLISTWITHHEAD_H__
#define __CIRCLELINKEDLISTWITHHEAD_H__

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

typedef int ElemType;

// 数据结点
struct node {
    ElemType data; // 数据域
    struct node *next; // 指针域
};

// 头结点的数据类型 保存链表的属性
struct list {
    struct node *first; // 指向第一个数据结点
    struct node *last; // 指向最后一个数据结点
    int NodeNum; // 记录链表的长度
    /*
        其他属性
    */
};

extern struct list* create_list();
extern void insert_node_order(struct list *list, ElemType d);
extern struct list* create_sort_list();
extern void print_list(struct list *list);
extern struct list* clear_list(struct list *list);
extern struct list* add_a_node(struct list *list, ElemType x, ElemType a);
extern struct list* delete_node(struct list *list, ElemType x);
extern void update_node(struct list *list, ElemType x, ElemType a);
extern struct list* destroy_list(struct list *list);
extern void sort_list(struct list *list);
extern void reverse_list(struct list *list);
extern bool GetElem(struct list *list, int pos, ElemType *val);
extern bool ListEmpty(struct list *list);
extern struct node* LocateElem1(struct list *list, ElemType e);
extern int LocateElem2(struct list *list, ElemType e);
extern bool insert_node(struct list *list, int i, ElemType e);
extern bool delete_a_node(struct list *list, int i, ElemType *e);

#endif

CircleLinkedListWithHead.c

#include "CircleLinkedListWithHead.h"

/*
    create_list:创建一个新链表,返回链表的首地址
*/
struct list* create_list() {
    ElemType d;
    struct node *pnew = NULL; // 指向新创建的结点

    // step0:创建一个头结点并初始化
    struct list *list = malloc(sizeof(*list));
    list->first = NULL; // 指向第一个数据结点
    list->last = NULL; // 指向最后一个数据结点
    list->NodeNum = 0; // 链表长度
    while (1) {
        // step1:每保存一个数据,就要创建一个结点(结构体)
        scanf("%d", &d);
        if (d == 0) {
            break;
        }
        pnew = malloc(sizeof(*pnew));
        list->NodeNum++; // 每创建一个新数据结点,属性NodeNum就加一
        // step2:把数据写入到结点中去
        pnew->data = d;
        pnew->next = NULL;
        // step3:把结点加入到链表中
        if (list->first == NULL) { // 从无到有,首尾结点都是pnew
            list->first = pnew;
            list->last = pnew;
        } else { // 从少到多
            // 尾插
            #if 1
            list->last->next = pnew; // list->last 指向新结点
            list->last = pnew; // list->last被pnew替代
            #endif
            #if 0
            // 头插
            pnew->next = list->first; // 新结点指向list->first
            list->first = pnew; // list->first被pnew替代
            #endif
        }
    }
    if (list->NodeNum != 0) {
        list->last->next = list->first;
    }   
    return list;
}

// 有序插入
void insert_node_order(struct list *list, ElemType d) {
    if (list == NULL) {
        return ;
    }
    // 创建一个新节点
    struct node *pnew = (struct node*)malloc(sizeof(*pnew));
    pnew->data = d;
    pnew->next = NULL;
    // 插入
    /*
        比第一个节点要小,头插法
        比最后一个结点要大 尾插法
        中间插,找第一个比它大的结点
    */
    if (list->first == NULL) { // 从无到有
        list->first = list->last = pnew;
    } else {
        struct node *p = list->first; // 遍历指针
        struct node *pre = NULL; // 指向遍历指针的前驱结点
        int len = list->NodeNum; // 链表长度
        while (len--) { // 找第一个比pnew大的结点
            if (p->data > pnew->data) {
                break;
            }   
            pre = p;
            p = p->next;
        }
        if (len == -1) { // 没有找到比它大 尾插
            list->last->next = pnew;
            list->last = pnew;
        } else { // 找到了
            if (p == list->first) { // 找到的结点为第一个结点
                // 头插
                pnew->next = list->first;
                list->first = pnew;
            } else {
                // 中间插
                pre->next = pnew;
                pnew->next = p;
            }
        }
    }
    list->NodeNum++;
    printf("%d\n", list->NodeNum);
    list->last->next = list->first;
}

/*
    create_sort_list:创建一个有序新链表,返回链表的首地址
*/
struct list* create_sort_list() {
    ElemType d;
    struct node *pnew = NULL; // 指向新创建的结点

    // step0:创建一个头结点并初始化
    struct list *list = malloc(sizeof(*list));
    list->first = NULL; // 指向第一个数据结点
    list->last = NULL; // 指向最后一个数据结点
    list->NodeNum = 0; // 链表长度
    while (1) {
        // step1:每保存一个数据,就要创建一个结点(结构体)
        scanf("%d", &d);
        if (d == 0) {
            break;
        }
        pnew = malloc(sizeof(*pnew));
        list->NodeNum++; // 每加入一个新结点,链表长度属性+1
        // step2:把数据写入到结点中去
        pnew->data = d;
        pnew->next = NULL;
        // step3:把结点加入到链表中
        if (list->first == NULL) { // 从无到有
            list->first = pnew;
            list->last = pnew;
        } else { // 从少到多
            struct node *p = list->first; // 指向链表的第一个数据结点,作用找到第一个比新结点大的那个结点
            struct node *pre = NULL; // 指向p指向的结点的前一个结点
            while (p) { // <==> p != NULL  遍历链表
                if (p->data > pnew->data) { // 找位置
                    break;
                } else { // 本结点不是,往后走
                    pre = p;
                    p = p->next;
                }
            }
            if (p != NULL) { // 找到了一个比pnew大的结点
                if (p == list->first) { // 头插
                    pnew->next = list->first;
                    list->first = pnew;
                } else { // 中间插
                    pre->next = pnew;
                    pnew->next = p;
                }
            } else { // 没找到 尾插
                pre->next = pnew;
                list->last = pnew; // 更新头结点的last属性 
            }
        }
    }
    if (list->NodeNum != 0) {
        list->last->next = list->first;
    }
    return list;
}

// 遍历遍历
void print_list(struct list *list) {
    if (list == NULL || list->NodeNum == 0) {
        return ;
    }
    struct node *p = list->first; // 遍历指针
    int len = list->NodeNum * 2;
    while (len--) {
        printf("%d ", p->data);
        p = p->next;
    }
    putchar('\n');
}

// 清空链表
struct list* clear_list(struct list *list) {
    if (list == NULL || list->NodeNum == 0) {
        return list;
    }
    // 变为普通单链表
    list->last->next = NULL;

    struct node *p = list->first; // 遍历指针
    struct node *pc = NULL; // 指向被拆结点
    while (p) { // 头删
        pc = p;
        p = p->next;
        pc->next = NULL;
        free(pc);
    }
    list->first = NULL;
    list->last = NULL;
    list->NodeNum = 0;
    return list;
}

/*
add_a_node:在链表h中值为x的结点前面,增加一个结点
    该结点的值为a,然后返回链表的首地址。
    假设没有值为x的结点,则在尾部增加。如果有多个值为x
    的结点则增加在第一个值为x的结点前面。
*/
struct list* add_a_node(struct list *list, ElemType x, ElemType a) {
    // 特殊情况
    if (list == NULL) {
        return NULL;
    }
    // step1:创建一个值为a的新结点
    struct node *pnew = malloc(sizeof(*pnew));
    pnew->data = a;
    pnew->next = NULL;

    if (list->first == NULL) { // 从无到有
        list->first = list->last = pnew;
    } else {
        struct node *p = list->first; // 遍历指针
        struct node *pre = NULL; // 指向p指向的结点的前一个结点
        // step2:找到值为x的结点
        int len = list->NodeNum;
        while (len--) {
            if (p->data == x) { // 找到了
                break;
            }
            // 没找到,往后走
            pre = p;
            p = p->next;
        }
        // step3:把新结点加入链表中
        if (len != -1) { // 找到了
            if (p == list->first) { // 头插
                pnew->next = list->first; // 新结点指向原链表的第一个数据结点
                list->first = pnew; // 更新头结点的first属性
            } else { // 中间插
                // pnew->next = p; // 新结点指向p指向的结点
                // pre->next = pnew; // p指向的结点的前一个结点 指向 新结点
                pre->next = pnew;
                pnew->next = p;
            }
        } else { // 没找到
            pre->next = pnew; // 尾插
            list->last = pnew; // 更新头结点的属性last
        }
    }
    list->NodeNum++; // 更新链表的长度
    list->last->next = list->first;
    return list;
}

/*
    delete_node:在h指向的链表中,删除值为x的结点
*/
struct list* delete_node(struct list* list, ElemType x) {
    // 特殊情况
    if (list == NULL || list->first == NULL) {
        return NULL;
    }
    struct node *p = list->first; // 遍历指针
    struct node *pre = NULL; // 指向p指向的结点的前一个结点
    // step1:找到值为x的结点
    int len = list->NodeNum;
    while (len--) {
        if (p->data == x) { // 找到了
            list->NodeNum--;
            // step2:删除值为x的结点
            if (p == list->first) { // 删除第一个数据结点
                list->first = list->first->next; // 如果链表只有一个结点,list->first->next = list->first
                p->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
                free(p);
                p = list->first;
                if (list->NodeNum == 0) { // 当删除到没有数据结点时
                    list->first = NULL; // 注意:这一步不能少
                    list->last = NULL;
                }
            } else if (p == list->last) { // 删除最后一个数据结点
                list->last = pre;
                list->last->next = NULL;
                p->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
                free(p);
            } else { // 删中间
                pre->next = p->next;
                p->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
                free(p);
                p = pre->next; // p往后走,pre不动
            }
        } else { // 没找到 往后走
            pre = p;
            p = p->next;
        }
    }
    if (list->NodeNum != 0) {
        list->last->next = list->first;
    }
    return list;
}

/*
    update_node:把list指向的链表中,值为x的结点的值改成a
*/
void update_node(struct list *list, ElemType x, ElemType a) {
    struct node *p = list->first; // 遍历指针
    int len = list->NodeNum;
    while (len--) {
        if (p->data == x) {
             p->data = a;
        }
        p = p->next;
    }
}

/*
    destroy_list:销毁单向循环链表
*/
struct list* destroy_list(struct list *list) {
    if (list == NULL) {
        return list;
    }
    if (list->last != NULL) {
        list->last->next = NULL; // 先把循环的属性去掉

        struct node *p = list->first; // 遍历指针
        struct node *pc = NULL; // 指向要拆的那个数据结点
        // 拆并释放数据结点
        while (p) { // 头删
            pc = p;
            p = p->next;
            pc->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
            free(pc);
        }
        list->first = NULL;
        list->last = NULL;
    }
    free(list); // 释放头结点
    list = NULL;
    return list;
}

// 对带头结点的循环单链表进行排序
void sort_list(struct list *list) {
    if (list == NULL || list->NodeNum == 0 || list->NodeNum == 1) {
        return ;
    }

    list->last->next = NULL; // 变成普通带头结点单链表

    // 1.遍历,将原来链表中的每一个结点依次摘下来
    struct node *head = list->first; // 遍历指针
    struct node *pc = NULL; // 要摘下来的结点

    list->first = NULL;
    list->last = NULL;

    // 2.将摘下来的结点 插入到新的链表中
    while (head) {
        // 摘
        pc = head;
        head = head->next;
        pc->next = NULL;
        // 加到链表
        if (list->first == NULL) { // 从无到有
            list->first = list->last = pc;
        } else {
            // 找第一个比插入结点大的结点p
            struct node *p = list->first; // 遍历指针
            struct node *pre = NULL; // 指向p指向的结点的前一个结点
            while (p) {
                if (p->data > pc->data) {
                    break;
                }   
                pre = p;
                p = p->next;
            }
            if (p == NULL) { // 没有找到 尾插
                list->last->next = pc;
                list->last = pc;
            } else { // 找到了
                if (p == list->first) { // 头插法
                    pc->next = list->first;
                    list->first = pc;
                } else { // 中间插
                    pre->next = pc;
                    pc->next = p;
                }
            }
        }
    }
    list->last->next = list->first; // 变回带头结点循环单链表
}

/*
逆置循环单链表(不能进行额外的申请结点)
    1.(直接交换数据域)
    2.(把原链表的每一个结点 摘下来,然后按照 头插法 插入到新的链表)
*/
void reverse_list(struct list *list) {
    if (list == NULL || list->NodeNum == 0 || list->NodeNum == 1) {
        return ;
    }

    list->last->next = NULL; // 变成普通带头结点单链表

	struct node *head = list->first; // 遍历指针
	struct node *pc = NULL; // 指向被拆结点

    list->first = NULL;
    list->last = NULL;

	while (head) {
		// 1.把原链表的每一个结点摘下来
        pc = head;
		head = head->next;
		pc->next = NULL;
		// 2.把摘下来的结点 按照头插法 插入
		if (list->first == NULL) { // 从无到有
            list->first = list->last = pc;
        } else { // 头插
			pc->next = list->first;
			list->first = pc;
		}
	}

    list->last->next = list->first; // 变回带头结点循环单链表
}

// 得到第i个元素的值
bool GetElem(struct list *list, int pos, ElemType *val) {
    // 特殊情况
    if (list == NULL || list->NodeNum == 0 || pos < 1 || pos > list->NodeNum) {
        return false;
    }

    list->last->next = NULL; // 变成普通带头结点单链表

    struct node *p = list->first; // 遍历指针
    int i = 1;
    while (p) {
        if (i == pos) {
            *val = p->data;    
            list->last->next = list->first; // 变回带头结点循环单链表
            return true;
        }
        i++;
        p = p->next;
    }
    list->last->next = list->first; // 变回带头结点循环单链表
    return false;
}

// 判断链表是否为空
bool ListEmpty(struct list *list) {
    if (list == NULL || list->NodeNum == 0) {
        return true;
    }
    return false;
}

/*
按值查找,返回地址
    在链表L中查找值为e的数据元素
    找到,则返回L中值为e的数据元素的地址,查找失败返回NULL
*/
struct node* LocateElem1(struct list *list, ElemType e) {
    if (list == NULL) {
        return NULL;
    }
    struct node *p = list->first; // 遍历指针
    int len = list->NodeNum;
    while (len-- && p->data != e) {
        p = p->next;
    }
    return p;
}

/*
按值查找,返回位置序号
    在链表L中查找第一个值为e的数据元素
    找到,则返回L中值为e的位置序号,查找失败返回0
*/
int LocateElem2(struct list *list, ElemType e) {
    if (list == NULL) {
        return 0;
    }
    struct node *p = list->first; // 遍历指针
    int j = 1;
    int len = list->NodeNum;
    while (len-- && p->data != e) {
        p = p->next;
        j++;
    }
    if (p) {
        return j;
    }
    return 0;
}

// 插入——在第i个结点前插入一个值为e的新结点
bool insert_node(struct list *list, int i, ElemType e) {
    // 特殊情况
    if (list == NULL || list->NodeNum == 0 || i < 1 || i > list->NodeNum) {
        return false;
    }
    // 变成普通带头结点单链表
    list->last->next = NULL;
    struct node *pnew = malloc(sizeof(*pnew)); // 创建一个新结点
    pnew->data = e;
    pnew->next = NULL;

    struct node *p = list->first; // 遍历指针
    struct node *pre = NULL; // 遍历指针的前驱结点
    int j = 1;
    while (j != i) {
        pre = p;
        p = p->next;
        j++;
    }
    if (p == list->first) { // 头插
        pnew->next = list->first;
        list->first = pnew;
    } else { // 中间插
        pre->next = pnew;
        pnew->next = p;
    }
    list->NodeNum++; // 链表长度+1
    list->last->next = list->first; // 变回带头结点循环单链表
    return true;
}

// 删除第i个结点
bool delete_a_node(struct list *list, int i, ElemType *e) {
    // 特殊情况
    if (list == NULL || list->NodeNum == 0 || i < 1 || i > list->NodeNum) {
        return false;
    }
    // 变成普通带头结点单链表
    list->last->next = NULL;

    struct node *p = list->first; // 遍历指针
    struct node *pre = NULL; // 遍历指针的前驱结点
    int j = 1;
    while (j != i) {
        pre = p;
        p = p->next;
        j++;
    }
    list->NodeNum--; // 链表长度减一
    if (p == list->first) { // 头删
        *e = p->data; // 保存被删结点数据
        list->first = list->first->next;
        p->next = NULL;
        free(p);
        if (list->NodeNum == 0) { // 当删除到没有数据结点时
            list->first = NULL;
            list->last = NULL;
        }
    } else if (p == list->last) { // 尾删
        list->last = pre;
        list->last->next = NULL;
        *e = p->data; // 保存被删结点数据
        free(p);
    } else { // 中间删
        *e = p->data;
        pre->next = p->next;
        p->next = NULL;
        free(p);
    }
    // 变回带头结点循环单链表
    if (list->NodeNum) {
        list->last->next = list->first;
    }
    return true;
}

main.c

#include "CircleLinkedListWithHead.h"

int main(int argc, char *argv[]) {
    // struct list *list = create_list(); // 创建一个新链表,返回链表的首地址
    struct list *list = create_sort_list(); // 创建一个有序新链表,返回链表的首地址
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    list = add_a_node(list, 3, 999);
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    list = delete_node(list, 999); // 删除值为999的结点
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    update_node(list, 3, 33); // 把链表中值为3的结点的值改成33
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    reverse_list(list); // 逆置链表
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    ElemType d;
    if (GetElem(list, 2, &d)) { // 得到第二个元素的值
        printf("第二个元素的值为:%d\n", d);
    }

    sort_list(list); // 对链表进行排序
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    insert_node_order(list, 99); // 有序插入99
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    if (LocateElem1(list, 33)) { // 按值查找,返回地址
        printf("%d的地址: %p\n", 33, LocateElem1(list, 33));
    }

    if (LocateElem2(list, 33)) { // 按值查找,返回位置序号
        printf("%d的序号: %d\n", 33, LocateElem2(list, 33));
    }
        
    if (insert_node(list, list->NodeNum, 111)) { // 插入——在第2个结点前插入一个新结点
        print_list(list); // 遍历遍历
        printf("链表长度为:%d\n", list->NodeNum);
    }
        
    while (!ListEmpty(list)) {
        if (delete_a_node(list, 1, &d)) {
            printf("第1个结点: %d被删除\n", d);
            print_list(list);
            printf("链表长度为:%d\n", list->NodeNum);
        }
    }
    
    list = destroy_list(list); // 销毁链表

    return 0;
}

带头循环双链表

BothWithCircleLinkedListWithHead.h

#ifndef __BOTHWITHCIRCLELINKEDLISTWITHHEAD_H__
#define __BOTHWITHCIRCLELINKEDLISTWITHHEAD_H__

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

typedef int ElemType;

// 数据结点
struct node {
    ElemType data; // 数据域 存储数据
    struct node *next; // 指针域 保存逻辑上的下一个(关系)
    struct node *prev; // 指针域 保存逻辑上的上一个(关系)
};

// 头结点的数据类型 保存链表的属性
struct list {
    struct node *first; // 指向第一个数据结点
    struct node *last; // 指向最后一个数据结点
    int NodeNum; // 记录链表的长度
    /*
        其他属性
    */
};

extern struct list* create_list();
extern void insert_node_order(struct list *list, ElemType d);
extern struct list* create_sort_list();
extern void print_list(struct list *list);
extern struct list* clear_list(struct list *list);
extern struct list* add_a_node(struct list *list, ElemType x, ElemType a);
extern struct list* delete_node(struct list *list, ElemType x);
extern void update_node(struct list *list, ElemType x, ElemType a);
extern struct list* destroy_list(struct list *list);
extern void sort_list_with_head(struct list *list);
extern void reverse_list(struct list *list);
extern bool GetElem(struct list *list, int pos, ElemType *val);
extern bool ListEmpty(struct list *list);
extern struct node* LocateElem1(struct list *list, ElemType e);
extern int LocateElem2(struct list *list, ElemType e);
extern bool insert_node(struct list *list, int i, ElemType e);
extern bool delete_a_node(struct list *list, int i, ElemType *e);

#endif

BothWithCircleLinkedListWithHead.c

#include "BothWithCircleLinkedListWithHead.h"

/*
    create_list:创建一个循环双链表,返回链表的首地址
*/
struct list* create_list() {
    ElemType d;
    struct node *pnew = NULL; // 指向新创建的结点
    // step0:创建一个头结点并初始化
    struct list *list = malloc(sizeof(*list));
    list->first = NULL; // 指向第一个数据结点
    list->last = NULL; // 指向最后一个数据结点
    list->NodeNum = 0; // 链表长度
    while (1) {
        // step1:每保存一个数据,就要创建一个结点(结构体)
        scanf("%d", &d);
        if (d == 0) {
            break;
        }
        pnew = malloc(sizeof(*pnew));
        list->NodeNum++; // 每创建一个新数据结点,属性NodeNum就加一
        // step2:把数据写入到结点中去
        pnew->data = d;
        pnew->next = NULL;
        pnew->prev = NULL;
        // step3:把结点加入到链表中
        if (list->first == NULL) { // 从无到有,首尾结点都是pnew
            list->first = pnew;
            list->last = pnew;
        } else { // 从少到多
            // 尾插
            #if 1
            list->last->next = pnew; // list->last 指向新结点
            pnew->prev = list->last;
            list->last = pnew; // list->last被pnew替代
            #endif
            #if 0
            // 头插
            pnew->next = list->first; // 新结点指向list->first
            list->first->prev = pnew;
            list->first = pnew; // list->first被pnew替代
            #endif
        }
    }
    if (list->NodeNum != 0) {
        list->last->next = list->first;
        list->first->prev = list->last;
    }
    return list;
}

// 有序插入
void insert_node_order(struct list *list, ElemType d) {
    if (list == NULL) {
        return ;
    }
    // 创建一个新节点
    struct node *pnew = (struct node*)malloc(sizeof(*pnew));
    pnew->data = d;
    pnew->next = NULL;
    pnew->prev = NULL;
    // 插入
    /*
        比第一个节点要小,头插法
        比最后一个结点要大 尾插法
        中间插,找第一个比它大的结点
    */
    if (list->first == NULL) { // 从无到有
        list->first = list->last = pnew;
    } else {
        struct node *p = list->first; // 遍历指针
        int len = list->NodeNum; //数据结点的个数
        while (len--) { // 找第一个比pnew大的结点
            if (p->data > pnew->data) {
                break;
            }  
            p = p->next;
        }
        if (len == -1) { // <==> p == NULL 没有找到比它大 尾插
            list->last->next = pnew;
            pnew->prev = list->last;
            list->last = pnew;
        } else {
            if (p == list->first) { // 找到的结点为第一个结点
                // 头插
                pnew->next = list->first;
                list->first->prev = pnew;
                list->first = pnew;
            } else {
                // 中间插
                pnew->next = p;
                pnew->prev = p->prev;
                p->prev->next = pnew;
                p->prev = pnew;
            }
        }
    }
    list->NodeNum++;
    // 首尾相连
    list->last->next = list->first;
    list->first->prev = list->last;
}

/*
    create_sort_list:创建一个新的有序循环双链表,返回链表的首地址
*/
struct list* create_sort_list() {
     ElemType d;
    struct node *pnew = NULL; // 指向新创建的结点
    // step0:创建一个头结点并初始化
    struct list *list = malloc(sizeof(*list));
    list->first = NULL; // 指向第一个数据结点
    list->last = NULL; // 指向最后一个数据结点
    list->NodeNum = 0; // 链表长度
    while (1) {
        // step1:每保存一个数据,就要创建一个结点(结构体)
        scanf("%d", &d);
        if (d == 0) {
            break;
        }
        pnew = malloc(sizeof(*pnew));
        list->NodeNum++;
        // step2:把数据写入到结点中去
        pnew->data = d;
        pnew->next = NULL;
        pnew->prev = NULL;
        // step3:把结点加入到链表中
        if (list->first == NULL) { // 数据结点从无到有
            list->first = pnew;
            list->last = pnew;
        } else { // 从少到多
            struct node *p = list->first; // 指向链表的第一个数据结点,找第一个比新结点大的那个结点
            while (p) { // <==> p != NULL  遍历链表
                if (p->data > pnew->data) { // 找位置
                    break;
                } else { //本结点不是,往后走
                    p = p->next;
                }
            }
            if (p != NULL) { // 找到有第一个比pnew大的结点
                if (p == list->first) { // 头插
                    pnew->next = list->first;
                    list->first->prev = pnew;
                    list->first = pnew;
                } else { // 中间插
                    pnew->next = p;
                    pnew->prev = p->prev;
                    p->prev->next = pnew;
                    p->prev = pnew;
                }
            } else { // 没找到 尾插
               list->last->next = pnew;
               pnew->prev = list->last;
               list->last = pnew; // 更新头结点的last属性
            }
        }
    }
    if (list->NodeNum != 0) { //链表不为空 首尾相连
        list->last->next = list->first;
        list->first->prev = list->last;
    }
    return list;
}

// 遍历遍历
void print_list(struct list *list) {
    // 异常处理
    if (list == NULL || list->NodeNum == 0) {
        return ;
    }
    struct node *p = list->first; // 遍历指针
    int len = list->NodeNum * 2;
    while (len--) {
        printf("%d ", p->data);
        p = p->next;
    }
    putchar('\n');
}

// 清空链表
struct list* clear_list(struct list *list) {
    if (list == NULL || list->NodeNum == 0) {
        return list;
    }
    // 变为普通双链表
    list->first->prev = NULL;
    list->last->next = NULL;

    struct node *p = list->first; // 遍历指针
    struct node *pc = NULL; // 指向被拆结点
    while (p) { // 头删
        pc = p;
        p = p->next;
        if (p) {
            p->prev = NULL;
        }
        pc->next = NULL;
        free(pc);
    }
    list->first = NULL;
    list->last = NULL;
    list->NodeNum = 0;
    return list; 
}

/*
add_a_node:在链表h中值为x的结点前面,增加一个结点
    该结点的值为a,然后返回链表的首地址。
    假设没有值为x的结点,则在尾部增加。如果有多个值为x
    的结点则增加在第一个值为x的结点前面。
*/
struct list* add_a_node(struct list *list, ElemType x, ElemType a) {
    // 异常处理
    if (list == NULL) {
        return NULL;
    }
    // step1:创建一个值为a的新结点
    struct node *pnew = malloc(sizeof(*pnew));
    pnew->data = a;
    pnew->next = NULL;
    pnew->prev = NULL;
    if (list->first == NULL) { // 从无到有
        list->first = list->last = pnew;
    } else {
        // step2:找到值为x的结点
        struct node *p = list->first; // 遍历指针
        while (p) { // while (p != NULL)
            if (p->data == x) { // 找到了
                break;
            }
            p = p->next; // 没找到,往后走
        }
        // step3:把新结点加入链表中
        if (p != NULL) { // 找到了
            if (p == list->first) { // 头插
                pnew->next = list->first; // 新结点指向原链表的第一个数据结点
                list->first->prev = pnew; 
                list->first=pnew; // 更新头结点的first属性
            } else { // 中间插
                pnew->next = p;
                pnew->prev = p->prev;
                p->prev->next = pnew;
                p->prev = pnew;
            }
        } else { // 没找到 尾插
            list->last->next = pnew;
            pnew->prev = list->last; 
            list->last = pnew; // 更新头结点的属性last
        }
    }
    list->NodeNum++; // 更新链表的长度
    // 变成循环双链表
    list->last->next = list->first;
    list->first->prev =list->last;
    return list;
}

/*
    delete_node:在h指向的链表中,删除值为x的结点
*/
struct list* delete_node(struct list *list, ElemType x) {
    // 异常处理
    if (list == NULL || list->first == NULL) {
        return NULL;
    }
    // 改成普通双链表
    list->first->prev = NULL;
    list->last->next = NULL;

    struct node* p = list->first; // 遍历指针
    // step1:找到值为x的结点
    while (p) {
        if (p->data == x) { // 找到了
            list->NodeNum--; // 链表长度减一
            // step2:删除值为x的结点
            if (p == list->first) { // 删除第一个数据结点
                list->first = list->first->next;
                if (list->first) {
                    list->first->prev = NULL;
                } else {
                    list->last = NULL;
                }
                p->next = NULL; // 为了工程规范,释放前把结点内的指针指向NULL
                free(p);
                p = list->first; // p往后走
            } else if (p == list->last) { // 删除最后一个数据结点
                list->last = p->prev;
                list->last->next = NULL;
                p->prev = NULL;
                free(p);
            } else { // 删中间
                struct node *psave = p->next; // 用psave保存p的下一个结点  save:保存
                p->prev->next = p->next;
                p->next->prev = p->prev;
                p->prev = NULL;
                p->next = NULL;
                free(p);
                p = psave; // p往后走
            }
        } else { // 没找到 往后走
            p = p->next;
        }
    }
    if (list->NodeNum != 0) { // 如果链表不为空,变回循环双链表
        list->last->next = list->first;
        list->first->prev =list->last;
    }
    return list;
}

/*
    update_node:把h指向的链表中,值为x的结点的值改成a
*/
void update_node(struct list *list, ElemType x, ElemType a) {
    struct node *p = list->first; // p是遍历指针
    int len = list->NodeNum;
    while (len--) {
        if (p->data == x) {
            p->data = a;
        }
        p = p->next;
    }
}

/*
    destroy_list:销毁双向循环链表
*/
struct list* destroy_list(struct list *list) {
    // 异常处理
    if (list == NULL) {
        return NULL;
    }
    if (list->first != NULL) { // 循环双链表不为空
        // 变成普通双链表
        list->first->prev = NULL;
        list->last->next = NULL;

        struct node *pc = list->first; // 指向被删结点
        while (pc) // 头删
        {
            list->first = list->first->next;
            if (list->first) {
                list->first->prev = NULL;
            }
            pc->next = NULL;
            free(pc);
            pc = list->first;
        }
        list->last = NULL; // 工程规范
        list->NodeNum = 0;
    }
    // 删除头结点
    free(list);
    list == NULL;
    return list;
}

// 对带头结点的循环双链表进行排序
void sort_list_with_head(struct list *list) {
    // 异常处理
    if (list == NULL || list->NodeNum == 0 || list->NodeNum == 1) {
        return ;
    }
    // 变成普通双链表
    list->first->prev = NULL;
    list->last->next = NULL;

    // 1.遍历,将原来链表中的每一个结点依次摘下来
    struct node *head = list->first; // 指向数据结点的第一个节点、遍历指针
    struct node *pc = NULL; // 要摘下来的结点

    list->first = NULL; 
    list->last = NULL;

    // 2.将摘下来的结点 插入到新的链表中
    while (head) {
        // 头摘
        pc = head;
        head = head->next;
        pc->next = NULL;
        pc->prev = NULL;
        // 加到链表
        if (list->first == NULL) { // 从无到有
            list->first = list->last = pc;
        } else {
            // 找第一个比插入结点大的结点p
            struct node *p = list->first; // 遍历指针
            while (p) {
                if(p->data > pc->data) {
                    break;
                }  
                p = p->next;
            }
            if (p == NULL) { // 没有找到 尾插
                list->last->next = pc;
                pc->prev = list->last;
                list->last = pc;
            } else {
                if (p == list->first) { // 头插法
                    pc->next = list->first;
                    list->first->prev = pc;
                    list->first = pc;
                } else { // 中间插
                    struct node *pre = p->prev;
                    pc->next = p;
                    pc->prev = pre;
                    pre->next = pc;
                    p->prev = pc;
                }
            }
        }
    }
    // 变回循环双链表
    list->first->prev = list->last;
    list->last->next = list->first;
}

/*
逆置循环双链表(不能进行额外的申请结点)
    1.(直接交换数据域)
    2.(把原链表的每一个结点 摘下来,然后按照 头插法 插入到新的链表)
*/
void reverse_list(struct list *list) {
    if (list == NULL || list->NodeNum == 0 || list->NodeNum == 1) {
        return ;
    }
    // 变成普通双链表
    list->first->prev = NULL;
    list->last->next = NULL;

	struct node *head = list->first; // 遍历指针
	struct node *pc = head; // 指向被拆结点

    list->first = NULL;
    list->last = NULL;

	while (head) {
		// 1.把原链表的每一个结点摘下来
        pc = head;
		head = head->next;
        if (head) {
            head->prev = NULL;
        }
		pc->next = NULL;
		// 2.把摘下来的结点 按照头插法 插入
		if (list->first == NULL) { // 从无到有
            list->first = list->last = pc;
        } else {
			pc->next = list->first;
            list->first->prev = pc;
			list->first = pc;
		}
	}
    // 变回循环双链表
    list->first->prev = list->last;
    list->last->next = list->first;
}

// 得到第i个元素的值
bool GetElem(struct list *list, int pos, ElemType *val) {
    if (list == NULL || list->NodeNum == 0 || pos < 1 || pos > list->NodeNum) {
        return false;
    }

    list->last->next = NULL;

    struct node *p = list->first;
    int i = 1;
    while (p) {
        if (i == pos) {
            *val = p->data;  
            list->last->next = list->first;
            return true;
        }
        i++;
        p = p->next;
    }
    list->last->next = list->first;
    return false;
}

// 判断链表是否为空
bool ListEmpty(struct list *list) {
    if (list == NULL || list->NodeNum == 0) {
        return true;
    }
    return false;
}

/*
按值查找,返回地址
    在链表L中查找值为e的数据元素
    找到,则返回L中值为e的数据元素的地址,查找失败返回NULL
*/
struct node* LocateElem1(struct list *list, ElemType e) {
    if (list == NULL) {
        return NULL;
    }
    list->last->next = NULL;
    struct node *p = list->first;
    while (p && p->data != e) {
        p = p->next;
    }
    list->last->next = list->first;
    return p;
}

/*
按值查找,返回位置序号
    在链表L中查找第一个值为e的数据元素
    找到,则返回L中值为e的位置序号,查找失败返回0
*/
int LocateElem2(struct list *list, ElemType e) {
    if (list == NULL) {
        return 0;
    }
    list->last->next = NULL;
    struct node *p = list->first; // 遍历指针
    int j = 1;
    // 不可写成while (p->data != e && p) 原因:段错误 短路 p最后指向空 
    while (p && p->data != e) {
        p = p->next;
        j++;
    }
    if (p) {
        list->last->next = list->first;
        return j;
    }
    list->last->next = list->first;
    return 0;
}

// 插入——在第i个结点前插入一个值为e的新结点
bool insert_node(struct list *list, int i, ElemType e) {
    // 异常处理
    if (list == NULL || list->NodeNum == 0 || i < 1 || i > list->NodeNum) {
        return false;
    }
    // 变成普通双链表
    list->first->prev = NULL;
    list->last->next = NULL;

    struct node *pnew = malloc(sizeof(*pnew)); // 创建一个新结点
    pnew->data = e;
    pnew->next = NULL;
    pnew->prev = NULL;

    struct node *p = list->first; // 遍历指针
    int j = 1;
    while (j != i) {
        p = p->next;
        j++;
    }
    if (j == 1) { // 头插
        pnew->next = list->first;
        list->first->prev = pnew;
        list->first = pnew;
    } else { // 中间插
        pnew->next = p;
        pnew->prev = p->prev;
        p->prev->next = pnew;
        p->prev = pnew;
    }
    list->NodeNum++; // 链表长度加1
    // 变回循环双链表
    list->first->prev = list->last;
    list->last->next = list->first;
    return true;
}

// 删除第i个结点
bool delete_a_node(struct list *list, int i, ElemType *e) {
    // 特殊情况
    if (list == NULL || list->NodeNum == 0 || i < 1 || i > list->NodeNum) {
        return false;
    }
    // 变成普通双链表
    list->first->prev = NULL;
    list->last->next = NULL;

    struct node *p = list->first; // 遍历指针
    int j = 1;
    while (j != i) {
        p = p->next;
        j++;
    }
    list->NodeNum--; // 链表长度减一
    if (j == 1) { // 头删
        list->first = list->first->next;
        if (list->first) {
            list->first->prev = NULL;
        } else { // 链表长度 == 0
            list->last = NULL;
        }
        *e = p->data; // 保存被拆结点数据
        p->next = NULL;
        free(p);
    } else if (p == list->last) { // 尾删
        list->last = p->prev;
        list->last->next = NULL;
        *e = p->data; // 保存被拆结点数据
        p->prev = NULL;
        free(p);
    } else { // 中间删
        struct node *pre = p->prev; // 被删结点的前驱结点
        *e = p->data; // 保存被拆结点数据
        pre->next = p->next;
        p->next->prev = pre;
        p->next = NULL;
        p->prev = NULL;
        free(p);
    }
    // 如果链表不为空,变回循环双链表
    if (list->NodeNum) {
        list->first->prev = list->last;
        list->last->next = list->first;
    }
    return true;
}

main.c

#include "BothWithCircleLinkedListWithHead.h"

int main(int argc, char *argv[]) {
    // struct list *list = create_list(); // 创建一个新链表,返回链表的首地址
    struct list *list = create_sort_list(); // 创建一个有序新链表,返回链表的首地址
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    list = add_a_node(list, 3, 999); // 在值为3的结点前面增加一个值为999的结点
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    list = delete_node(list, 999); // 删除值为999的结点
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    update_node(list, 3, 33); // 把链表中值为3的结点的值改成33
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    reverse_list(list); // 逆置链表
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    ElemType d;
    if (GetElem(list, 2, &d)) { // 得到第二个元素的值
        printf("第二个元素的值为:%d\n", d);
    }

    sort_list_with_head(list); //对链表进行排序
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    insert_node_order(list, 99); //有序插入99
    print_list(list); // 遍历遍历
    printf("链表长度为:%d\n", list->NodeNum);

    if (LocateElem1(list, 33)) { // 按值查找,返回地址
        printf("%d的地址: %p\n", 33, LocateElem1(list, 33));
    }

    if (LocateElem2(list, 33)) { // 按值查找,返回位置序号
        printf("%d的序号: %d\n", 33, LocateElem2(list, 33));
    }
        
    if (insert_node(list, list->NodeNum, 111)) { // 插入——在第2个结点前插入一个新结点
        print_list(list); // 遍历遍历
        printf("链表长度为:%d\n", list->NodeNum);
    }
        
    while (!ListEmpty(list)) {
        if (delete_a_node(list, 1, &d)) {
            printf("第1个结点: %d被删除\n", d);
            print_list(list);
            printf("链表长度为:%d\n", list->NodeNum);
        }
    }
    
    list = destroy_list(list); // 销毁链表

    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值