数据结构(邓俊辉):列表及相关概念_listnodeposi-CSDN博客
#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;
}
调试
// 测试函数
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博客