数据结构(邓俊辉):列表及相关概念_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
:也就是尾哨兵节点,它位于链表的末尾,同样不存储实际的数据。它的作用是作为链表最后一个有效节点的后继节点。