复杂链表+OJ
链表的分类
1.单向or双向
2.带头or不带头(哨兵位头结点)
3.循环or不循环
1.无头单向非循环链表
这个链表我们前面已经讲过了,想详细了解的可以去看单链表详解。
2.带头双向循环链表
这个是我们本章节的重点,下面细讲。
总结:
带头双向循环链表的实现
结构
typedef int LTDateType;
typedef struct ListNode
{
//存储数据
LTDateType date;
//保存下一个节点的地址
struct ListNode* next;
//保存上一个节点的地址
struct ListNode* prev;
}ListNode;
接口有哪些呢?
// 创建返回链表的头结点.(初始化)
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDateType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDateType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDateType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDateType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);
接下来我们来一一实现:
初始化
// 创建返回链表的头结点.
ListNode* ListCreate()
{
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
//判断是否开辟成功
if (node == NULL)
{
perror("malloc fail");
exit(-1);
}
//初始化
node->next = node;
node->prev = node;
node->date = 0;
return node;
}
打印链表
// 双向链表打印
void ListPrint(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->next;
while (cur != pHead)
{
printf("%d->", cur->date);
cur = cur->next;
}
printf("\n");
}
尾插
ListNode* BuyListNode(int x)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
//节点里面的指针可以初始化为NULL,因为他们暂时无任何指向。
newnode->date = x;
newnode->next = NULL;
newnode->prev = NULL;
return newnode;
}
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDateType x)
{
assert(pHead);
ListNode* newnode = BuyListNode(x);
ListNode* tail = pHead->prev;
tail->next = newnode;
newnode->next = pHead;
pHead->prev = newnode;
newnode->prev = tail;
}
头插
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDateType x)
{
assert(pHead);
ListNode* newnode = BuyListNode(x);
newnode->prev = pHead;
newnode->next = pHead->next;
pHead->next->prev = newnode;
pHead->next = newnode;
}
尾删
// 双向链表尾删
void ListPopBack(ListNode* pHead)
{
assert(pHead);
//链表为空就别删了
assert(pHead->next != pHead);
//保存尾节点
ListNode* tail = pHead->prev;
//保存尾节点的前一个节点
ListNode* tailPrev = tail->prev;
//释放尾节点
free(tail);
//改变链接关系
tailPrev->next = pHead;
pHead->prev = tailPrev;
}
头删
// 双向链表头删
void ListPopFront(ListNode* pHead)
{
assert(pHead);
assert(pHead->next != pHead);
ListNode* first = pHead->next;
pHead->next = first->next;
first->next->prev = pHead;
free(first);
}
查找
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDateType x)
{
ListNode* cur = pHead->next;
while (cur != pHead)
{
if (cur->date == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
在pos前面插入
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDateType x)
{
assert(pos);
ListNode* posPrev = pos->prev;
ListNode* newnode = BuyListNode(x);
posPrev->next = newnode;
newnode->prev = posPrev;
newnode->next = pos;
pos->prev = newnode;
}
删除pos位置的数据
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{
assert(pos);
pos->prev->next = pos->next;
pos->next->prev = pos->prev;
free(pos);
}
销毁链表
// 双向链表销毁
void ListDestory(ListNode* pHead)
{
ListNode* cur = pHead->next;
while (cur != pHead)
{
ListNode* del = cur;
cur = cur->next;
free(del);
}
free(pHead);
}
链表和顺序表的区别
下图是缓存的一些知识:
用随机指针复制列表
第一步:
第二步;
改变拷贝链表的random的值,他就是原链表的random的next。
第三步
就是恢复链表,并且将拷贝的拿来尾插成新的链表。
代码如下:
struct Node* copyRandomList(struct Node* head)
{
struct Node* cur = head;
//第一步插入copy
while(cur)
{
struct Node* next = cur->next;
struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
//拷贝
copy->val = cur->val;
//改变链接关系
cur->next = copy;
copy->next = next;
//cur迭代
cur = copy->next;
}
cur = head;
//第二步,改变copy的random
while(cur)
{
struct Node* copy = cur->next;
if(cur->random==NULL)
{
copy->random=NULL;
}
else
{
copy->random = cur->random->next;
}
cur = copy->next;
}
//第三步 尾插并且恢复原链表
cur = head;
struct Node* copyhead = NULL,*copytail = NULL;
while(cur)
{
struct Node* copy = cur->next;
struct Node* next = copy->next;
//尾插copy
if(copyhead==NULL)
{
copyhead=copytail=copy;
}
else
{
copytail->next = copy;
copytail = copytail->next;
}
//恢复原链表
cur->next = next;
cur = next;
}
return copyhead;
}
今天的分享就到这里,感谢大家的关注和支持。