列表之链表_C

数据结构(邓俊辉):列表及相关概念_listnodeposi-CSDN博客

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

// 定义Rank类型为int
typedef int Rank;

// 定义ListNode结构体
typedef struct ListNode {
    int data;
    struct ListNode* pred;
    struct ListNode* succ;
} ListNode;

// 定义List结构体
typedef struct List {
    int _size;
    ListNode* header;
    ListNode* trailer;
} List;

// 链表初始化函数
void init(List* list) {
    list->header = (ListNode*)malloc(sizeof(ListNode));
    list->trailer = (ListNode*)malloc(sizeof(ListNode));
    list->header->succ = list->trailer;
    list->header->pred = NULL;
    list->trailer->pred = list->header;
    list->trailer->succ = NULL;
    list->_size = 0;
}

// 查找函数
ListNode* find(List* list, int e, int n, ListNode* p) {
    while (0 < n--) {
        if (e == (p = p->pred)->data) {
            return p;
        }
    }
    return NULL;
}

// 作为首节点插入函数
ListNode* insertAsFirst(List* list, int e) {
    list->_size++;
    return list->header->succ = list->header->insertAsSucc(e);
}

// 作为末节点插入函数
ListNode* insertAsLast(List* list, int e) {
    list->_size++;
    return list->trailer->pred = list->trailer->insertAsPred(e);
}

// 作为p的后继插入函数
ListNode* insertA(List* list, ListNode* p, int e) {
    list->_size++;
    return p->insertAsSucc(e);
}

// 作为p的前驱插入函数
ListNode* insertB(List* list, ListNode* p, int e) {
    list->_size++;
    return p->insertAsPred(e);
}

// 节点作为前驱插入函数
ListNode* insertAsPred(ListNode* p, int e) {
    ListNode* x = (ListNode*)malloc(sizeof(ListNode));
    x->data = e;
    x->pred = p->pred;
    x->succ = p;
    p->pred->succ = x;
    p->pred = x;
    return x;
}

// 节点作为后继插入函数
ListNode* insertAsSucc(ListNode* p, int e) {
    ListNode* x = (ListNode*)malloc(sizeof(ListNode));
    x->data = e;
    x->pred = p;
    x->succ = p->succ;
    p->succ->pred = x;
    p->succ = x;
    return x;
}

// 复制节点函数
void copyNOdes(List* list, ListNode* p, int n) {
    init(list);
    while (n--) {
        insertAsLast(list, p->data);
        p = p->succ;
    }
}

// 删除节点函数
int removeNode(List* list, ListNode* p) {
    int e = p->data;
    p->pred->succ = p->succ;
    p->succ->pred = p->pred;
    free(p);
    list->_size--;
    return e;
}

// 析构函数
void destroyList(List* list) {
    clear(list);
    free(list->header);
    free(list->trailer);
}

// 清除所有节点函数
int clear(List* list) {
    int oldSize = list->_size;
    while (0 < list->_size) {
        removeNode(list, list->header->succ);
    }
    return oldSize;
}

// 无序去重函数
int deduplicate(List* list) {
    if (list->_size < 2) {
        return 0;
    }
    int oldSize = list->_size;
    ListNode* p = list->header;
    Rank r = 0;
    while (list->trailer != (p = p->succ)) {
        ListNode* q = find(list, p->data, r, p);
        if (q) {
            removeNode(list, q);
        } else {
            r++;
        }
    }
    return oldSize - list->_size;
}

// 有序去重函数
int uniquify(List* list) {
    if (list->_size < 2) {
        return 0;
    }
    int oldSize = list->_size;
    ListNode* p = list->header->succ;
    ListNode* q;
    while (list->trailer != (q = p->succ)) {
        if (p->data != q->data) {
            p = q;
        } else {
            removeNode(list, q);
        }
    }
    return oldSize - list->_size;
}

// 遍历函数
void traverse(List* list, void (*visit)(int*)) {
    for (ListNode* p = list->header->succ; p != list->trailer; p = p->succ) {
        visit(&p->data);
    }
}

// 查找函数(有序区间查找)
ListNode* search(List* list, int e, int n, ListNode* p) {
    while (0 <= n--) {
        if (((p = p->pred)->data) <= e) {
            break;
        }
    }
    return p;
}

调试

cpp 复制代码
// 测试函数
void printData(int* data) {
    printf("%d ", *data);
}

int main() {
    List list;
    init(&list);

    // 插入节点测试
    insertAsFirst(&list, 1);
    insertAsLast(&list, 3);
    insertA(&list, list.header->succ, 2);

    // 遍历测试
    traverse(&list, printData);
    printf("\n");

    // 查找测试
    ListNode* found = find(&list, 2, list._size, list.trailer);
    if (found) {
        printf("找到节点,值为:%d\n", found->data);
    } else {
        printf("未找到节点\n");
    }

    // 无序去重测试
    deduplicate(&list);
    traverse(&list, printData);
    printf("\n");

    // 有序去重测试
    insertAsLast(&list, 3);
    uniquify(&list);
    traverse(&list, printData);
    printf("\n");

    // 清除并销毁链表
    destroyList(&list);

    return 0;
}

在链表相关的数据结构中,"succ" 是 "successor" 的缩写,意思是 "后继者、继任者" 。在链表节点的定义中,将指针命名为 succ 就是用来指向当前节点的下一个节点,即后继节点。

这里的 pred 是 "predecessor" 的缩写,表示 "前驱者、前一个" ,pred 指针指向当前节点的前一个节点;

  • header:即头哨兵节点,它处于链表的起始位置,但并不存储实际的数据。其主要用途是作为链表第一个有效节点的前驱节点,便于对链表的操作。
  • trailer:也就是尾哨兵节点,它位于链表的末尾,同样不存储实际的数据。它的作用是作为链表最后一个有效节点的后继节点。

数据结构(邓俊辉):列表及相关概念_listnodeposi-CSDN博客

相关推荐
_x_w1 小时前
【16】数据结构之基于树的排序算法篇章
开发语言·数据结构·python·算法·链表·排序算法
come on world1 小时前
入门51单片机(1)-----点灯大师梦开始的地方
c语言·单片机·嵌入式硬件·学习·51单片机
小林熬夜学编程2 小时前
【高阶数据结构】第三弹---图的存储与遍历详解:邻接表构建与邻接矩阵的BFS/DFS实现
c语言·数据结构·c++·算法·深度优先·图论·宽度优先
大锦终2 小时前
【C++】多态
c语言·开发语言·数据结构·c++
Awesome Baron3 小时前
jupyter中切换Anaconda虚拟环境
windows·python·jupyter
庸子3 小时前
Active Directory域服务管理与高级应用技术白皮书
运维·服务器·网络·windows·ad
牧木江3 小时前
【从C到C++的算法竞赛迁移指南】第二篇:动态数组与字符串完全攻略 —— 写给C程序员的全新世界
c语言·c++·经验分享·笔记·算法
祁同伟.3 小时前
【数据结构 · 初阶】- 带头双向循环链表
数据结构·链表
21号 14 小时前
21.C++11
windows
fly spider6 小时前
一站式Windows下Docker开启MySQL并链接本地Navicat(附乱码解决方案)
windows·mysql·docker·乱码解决