不知道各位有没有看过一部国漫——《刺客伍六七》。在我这个血统并不算纯的二次元来说,这部动漫无论从剧情还是打斗等各个方面,都可以算的上是动漫中的一流作品了。/*仅仅在我看过的动漫中*/
当然这篇博客的主题肯定不是来讲动漫的。我们今天的主题正如标题所言,是数据结构的一大地基——链表。在我的见闻中,链表此物,与刺客伍六七中主角阿柒的“专武”——神锻国国宝——魔刀千刃,有着异曲同工之妙。与普通的刀剑(顺序表)不同,魔刀千刃(链表)由一片片碎片组成,可以随主人的心意作为一个整体的刀或分解为一个个碎片来进攻敌人,号称只攻不防,天下无双。
链表当然没有魔刀千刃这么离谱,但也很像。链表与魔刀千刃的千刃追月形态(见第一季最后一集)一样,它们是一个完整的整体,却零散的分布在空间(也就是我们的内存)中。顺序是可循的,不同的碎片与碎片之间有着千丝万缕的联系(指针)。
概念:链表是一种 物理存储结构上非连续 、非顺序的存储结构,数据元素的 逻辑顺序 是通过链表中的 指针链 接 次序实现的 。
核心要点:通过结构体定义一种数据类型,由所存储元素及其同类型(即该结构体类型)指针组成。
以双向链表为例:
typedef struct ListNode
{
LTDataType _data;
struct ListNode* _next;
struct ListNode* _prev;
}ListNode;
_data中存储的是该单位的数据。
_next是指向链表下一个元素的指针。
_prev指向上一个元素的指针。
我们通过指针来使链表成为一个整体,从而对其进行各种各样的操作。与顺序表一般的方便,并且可以更加高效的利用内存,使用内存中细小的不连续的空间,还可以灵活的扩展或者减少空间。
除了查找效率比较低以及更容易出错之外,它几乎没有缺点(手动狗头)
ListNode* ListCreate() {
ListNode* head = (ListNode*)malloc(sizeof(ListNode));
assert(head);
head->_next = head;
head->_prev = head;
return head;
}
// 双向链表销毁
void ListDestory(ListNode* pHead) {
ListNode* tmp;
ListNode* pre;
tmp = pHead->_next;
while (pHead != tmp) {
pre = tmp;
tmp = pre->_next;
free(pre);
}
free(pHead);
pHead = NULL;
}
// 双向链表打印
void ListPrint(ListNode* pHead) {
assert(pHead);
ListNode* tmp;
tmp = pHead->_next;
while (pHead != tmp) {
printf("%d ", tmp->_data);
tmp = tmp->_next;
}
printf("\n");
}
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x) {
assert(pHead);
ListNode* tail = (ListNode*)malloc(sizeof(ListNode));
assert(tail);
ListNode* pFro = pHead->_prev;
pHead->_prev = tail;
pFro->_next = tail;
tail->_next = pHead;
tail->_data = x;
tail->_prev = pFro;
}
// 双向链表尾删
void ListPopBack(ListNode* pHead) {
assert(pHead);
ListNode* pFro = pHead->_prev;
ListNode* pBack = pFro->_prev;
pBack->_next = pHead;
pHead->_prev = pBack;
free(pFro);
}
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x) {
assert(pHead);
ListNode* top = (ListNode*)malloc(sizeof(ListNode));
assert(top);
ListNode* pFro = pHead->_next;
pHead->_next = top;
pFro->_prev = top;
top->_prev = pHead;
top->_data = x;
top->_next = pFro;
}
// 双向链表头删
void ListPopFront(ListNode* pHead) {
assert(pHead);
ListNode* pFro = pHead->_next;
ListNode* pBack = pFro->_next;
pBack->_prev = pHead;
pHead->_next = pBack;
free(pFro);
}
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x) {
assert(pHead);
ListNode* tmp = pHead->_next;
while (tmp != pHead) {
if (x == tmp->_data) {
return tmp;
}
tmp = tmp->_next;
}
printf("找不到该目标位置");
return pHead;
}
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x) {
ListNode* prev = pos->_prev;
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
newnode->_data = x;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = pos;
pos->_prev = newnode;
}
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos) {
assert(pos);
ListNode* prev = pos->_prev;
ListNode* next = pos->_next;
free(pos);
prev->_next = next;
next->_prev = prev;
}