文章目录
一、双向链表的实现
1.双向链表的创建
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* next;
struct ListNode* prev;
LTDataType data;
}LTNode;
2.创建节点
LTNode* BuyListNode(LTDataType x)
{
LTNode* node = (LTNode*)malloc(sizeof(LTNode));
if (node == NULL)
{
perror("malloc fail");
exit(-1);
}
node->data = x;
node->next = NULL;
node->prev = NULL;
return node;
}
3.初始化
LTNode* ListInit()
{
LTNode* phead = BuyListNode(-1);
phead->next = phead;
phead->prev = phead;
return phead;
}
4.尾插
void ListPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = BuyListNode(x);
LTNode* tail = phead->prev;
tail->next = newnode;
newnode->prev = tail;
newnode->next = phead;
phead->prev = newnode;
}
5.尾删
void ListPopBack(LTNode* phead)
{
assert(phead);
assert(!ListEmpty(phead));
LTNode* tail = phead->prev;
LTNode* tailPrev = tail->prev;
free(tail);
tailPrev->next = phead;
phead->prev = tailPrev;
}
6.头插
void ListPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = BuyListNode(x);
LTNode* next = phead->next;
phead->next = newnode;
newnode->prev = phead;
newnode->next = next;
next->prev = newnode;
}
7.头删
void ListPopFront(LTNode* phead)
{
assert(phead);
assert(!ListEmpty(phead));
LTNode* next = phead->next;
LTNode* Next = next->next;
phead->next = Next;
Next->prev = phead;
free(next);
}
8.销毁
void ListDestory(LTNode* phead)
{
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}
9.查找
LTNode* ListFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
10.打印
void ListPrint(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
11.判断链表是否为空
bool ListEmpty(LTNode* phead)
{
assert(phead);
return phead->next == phead;
}
12.在指定位置上插入
// 在pos位置之前插入x
void ListInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* prev = pos->prev;
LTNode* newnode = BuyListNode(x);
// prve newnode pos
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos;
pos->prev = newnode;
}
13.在指定位置上删除
// 删除pos位置的节点
void ListErase(LTNode* pos)
{
assert(pos);
LTNode* prev = pos->prev;
LTNode* next = pos->next;
prev->next = next;
next->prev = prev;
free(pos);
}
14.求链表的长度
int ListSize(LTNode* phead)
{
assert(phead);
int length = 0;
LTNode* cur = phead->next;
while (cur != phead) {
length++;
cur = cur->next;
}
return length;
}
二、顺序表与链表的区别
顺序表的优点:支持随机访问 缓存利用率
顺序表的缺点:头部或者中间插入删除效率低、扩容(有一定的性能消耗,可能存在一定程度的空间浪费)。
缓存利用率高
链表的优点:在任何位置插入删除为O(1),按需申请释放。
链表的缺点:不支持下标的随机访问。
缓存利用率低
注意:数据结构是在内存中增删查改。
三、关于双向链表的题目
复制带随机指针的链表OJ链接
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}
};
*/
class Solution {
public:
Node* copyRandomList(Node* head) {
Node*cur=head;
//第一步将原链表拷贝
while(cur)
{
Node*copy=new Node(cur->val,cur->next);
cur->next=copy;
cur=copy->next;
}
cur=head;
//第二步将链表进行改变random指针
while(cur)
{
Node*copy=cur->next;
if(cur->random==nullptr)
{
copy->random=nullptr;
}
else
{
copy->random=cur->random->next;
}
cur=copy->next;
}
cur=head;
Node*copyhead=nullptr,*copytail=nullptr;
//第三步将链表尾插到新的链表中
while(cur)
{
Node*copy=cur->next;
Node*next=copy->next;
if(copytail==nullptr)
copyhead=copytail=copy;
else
{
copytail->next=copy;
copytail=copytail->next;
}
cur->next=next;
cur=next;
}
return copyhead;
}
};