目录
一、无头单线非循环链表
1.大致结构
这种链表结构简单,但增删相较另一种较为复杂。
2.实现增删查改
SListNode* BuySListNode(SLTDateType x)
{
SListNode* newnode=(SListNode*)malloc(sizeof(SListNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
SListNode* CreatSList(int n)
{
SListNode* phead = NULL;
SListNode* plist = NULL;
for (int i = 0; i < n; i++)
{
SListNode* newnode = BuySListNode(i);
if (phead == NULL)
{
plist=phead = newnode;
}
else
{
plist->next = newnode;
plist = newnode;
}
}
return phead;
}
void SListPrint(SListNode* plist)
{
SListNode* cur = plist;
while (cur!=NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
void SListPushBack(SListNode** pplist, SLTDateType x)
{
SListNode* newnode = BuySListNode(x);
if (*pplist == NULL)
{
*pplist = newnode;
}
else
{
SListNode* tail = *pplist;
//找尾
while (tail->next)
{
tail = tail->next;
}
tail->next = newnode;
}
}
void SListPushFront(SListNode** pplist, SLTDateType x)
{
SListNode* newnode = BuySListNode(x);
newnode->next = *pplist;
*pplist = newnode;
}
void SListPopBack(SListNode** pplist)
{
assert(*pplist);
if ((*pplist)->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
SListNode* tail = *pplist;
while (tail->next->next)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
/*SListNode* prev = NULL;
while (tail->next)
{
prev = tail;
tail = tail->next;
}
free(tail);
prev->next = NULL;*/
}
}
void SListPopFront(SListNode** pplist)
{
assert(*pplist);
SListNode* next = (*pplist)->next;
free(*pplist);
*pplist = next;
}
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
assert(plist);
SListNode* cur = plist;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
assert(pos);
SListNode* newnode = BuySListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
void SListEraseAfter(SListNode* pos)
{
assert(pos);
if (pos->next == NULL)
return;
SListNode* cur = pos->next;
pos->next = cur->next;
free(cur);
}
void SListDestroy(SListNode** pplist)
{
SListNode* cur = *pplist;
while (cur)
{
SListNode* next = cur->next;
free(cur);
cur=next;
}
*pplist = NULL;
}
3.说明
1)哨兵位
因为不带头节点,尾插时可能会有问题。所以在我们做oj题目时可以自己创造哨兵位来简化尾插。
2)二级指针问题
因为头删、头插等问题会改变头指针,所以单链表可能会应用到二级指针来改变头指针。
二、有头双向循环链表
1.大致结构
2.实现增删查改
ListNode* BuyListNode(LTDataType x)
{
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
if (node == NULL)
{
perror("fail malloc");
exit(-1);
}
node->data = x;
node->next = NULL;
node->prev = NULL;
return node;
}
ListNode* LTInit()
{
ListNode* phead = BuyListNode(-1);
phead->next = phead;
phead->prev = phead;
return phead;
}
void ListPushBack(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* newnode = BuyListNode(x);
ListNode* tail = pHead->prev;
newnode->prev = tail;
newnode->next = pHead;
tail->next = newnode;
pHead->prev = newnode;
}
void ListPrint(ListNode* pHead)
{
assert(pHead);
ListNode* Rhead = pHead->next;//当Rhead==哨兵位时 说明遍历了一遍了
while (Rhead != pHead)
{
printf("%d->", Rhead->data);
Rhead = Rhead->next;
}
printf("NULL\n");
}
void ListPopBack(ListNode* pHead)
{
assert(pHead);
assert(pHead->next != pHead);
ListNode* tt = pHead->prev;
ListNode* tail = pHead->prev->prev;
tail->next = pHead;
pHead->prev = tail;
free(tt);
}
void ListPushFront(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* newnode = BuyListNode(x);
ListNode* next = pHead->next;
newnode->next = next;
newnode->prev = pHead;
pHead->next = newnode;
next->prev = newnode;
}
void ListPopFront(ListNode* pHead)
{
assert(pHead);
assert(pHead->next != pHead);
ListNode* next = pHead->next;
ListNode* nnext = next->next;
pHead->next = nnext;
nnext->prev = pHead;
free(next);
}
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* cur = pHead->next;
while (cur != pHead)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
return NULL;
}
void ListInsert(ListNode* pos, LTDataType x)
{
ListNode* newnode = BuyListNode(x);
ListNode* tail = pos->prev;
tail->next = newnode;
newnode->next = pos;
newnode->prev = tail;
pos->prev = newnode;
}
void ListErase(ListNode* pos)
{
assert(pos);
ListNode* prev = pos->prev;
ListNode* next = pos->next;
prev->next = next;
next->prev = prev;
free(pos);
}
void ListDestory(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->next;
while (cur != pHead)
{
ListNode* next = cur->next;
free(cur);
cur = next;
}
free(pHead);
}
3.说明
1)非常优越
虽然该结构较为复杂,但是实现增删查改非常方便。prev指针和next指针在头插尾插等活动性能非常优越。
2)应用方面
数据结构单链表经常会和别的数据结构结合使用,当单独使用链表时该链表优渥。
END
简单介绍一下两种链表结构,链表结构并不是只有这两种。笔者仅介绍两种具有代表性的结构。下一篇博客将会介绍Leetcode上的单链表典型题目,敬请关注。