0
点赞
收藏
分享

微信扫一扫

C++、python双语言弹窗教程与对比

正义的杰克船长 2023-08-08 阅读 53

在这里插入图片描述

复杂链表+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;
}

今天的分享就到这里,感谢大家的关注和支持。

举报

相关推荐

0 条评论