数据结构:单链表的操作

单链表要实现增删改查,反转,置空等功能

分为三部分test.c ,SList.c, SList.h
以下为源代码:
*test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "Slist.h"
#include <stdlib.h>
void menu()
{
	printf("**  1.尾部插入             2.尾部删除               **\n");
	printf("**  3.头部插入             4.头部删除               **\n");
	printf("**  5.任意位置插入         6.任意位置删除           **\n");
	printf("**  7.统计节点个数         8.返回第一个值           **\n");
	printf("**  9.返回最后一个值       10.显示                  **\n");
	printf("**  11.释放                12.置空                  **\n");
	printf("**  13.逆置                14.删除指定的所有值      **\n");
	printf("**  15.删除指定的所有值第二种方法                   **\n");
}
void test()
{
	SList pl;
	SListInit(&pl);
	int input = 0;
	SDataType data;
	SDataType val;
	int count = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入要插入的数:");
			scanf("%d", &data);
			SListPushBack(&pl, data);
			break;
		case 2:
			SListPopBack(&pl);
			break;
		case 3:
			printf("请输入要插入的数:");
			scanf("%d", &data);
			SListPushFront(&pl, data);
			break;
		case 4:
			SListPopFront(&pl);
			break;
		case 5:
			printf("请输入要插入哪个数后面:");
			scanf("%d", &val);
			printf("请输入插入的数:");
			scanf("%d", &data);
			SListInsertAfter(SListFind(&pl, val), data);
			break;
		case 6:
			printf("请输入要删除的数:");
			scanf("%d", &val);
			SListErase(&pl, SListFind(&pl, val));
			break;
		case 7:
			count = SListSize(&pl);
			printf("节点个数为:%d\n", count);
			break;
		case 8:
			data=SListFront(&pl);
			printf("第一个值为:%d\n", data);
			break;
		case 9:
			data=SListBack(&pl);
			printf("最后一个值为:%d\n", data);
			break;
		case 10:
			PrintSList(&pl);
			break;
		case 11:
			SListDestroy(&pl);
			break;
		case 12:
			SListEmpty(&pl);
			printf("置空成功!\n");
			break;
		case 13:
			ReverseSList(&pl);
			break;
		case 14:
			printf("请输入要删除的值:");
			scanf("%d", &data);
			removeElements1(&pl, data);//删除所有为data的值
			break;
		case 15:
			printf("请输入要删除的值:");
			scanf("%d", &data);
			removeElements2(&pl, data);//删除所有为data的值
			break;

		}
	} while (input);
}
int main()
{
	test();
	system("pause");
	return 0;
}
  • SList.h
#pragma once
typedef int SDataType;
typedef struct SListNode
{
	SDataType _data;
	struct SListNode* _pNext;
}Node;
typedef struct SList
{
	Node* pHead;
}SList;
void SListInit(SList *pl);
void SListPushBack(SList *pl, SDataType data);//尾插
void SListPopBack(SList *pl);//尾删
void SListPushFront(SList *pl, SDataType data);//头插
void SListPopFront(SList *pl);//头删
void SListInsertAfter(Node *pos, SDataType data);//任意位置插入
void SListErase(SList *pl, Node *pos);//任意位置删除
Node *SListFind(SList *pl, SDataType data);//查找
int SListSize(SList *pl);//找寻节点个数
SDataType SListFront(SList *pl);//获取第一个节点
SDataType SListBack(SList *pl);//必须保证有尾结点,获取最后一个节点
void PrintSList(SList *pl);
void SListDestroy(SList *pl);
int SListEmpty(SList *pl);
Node* ReverseSList(SList *pl);
Node* removeElements1(SList *pl, SDataType val);//删除所有为val的值
Node *removeElements2(SList *pl, SDataType val);//删除所有为val的结点第二种方法
  • SList.c
#include "SList.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void SListInit(SList *pl)
{
	assert(pl);
	pl->pHead = NULL;
}
Node* BuySListNode(SDataType data)//构造结点
{
	Node* pNewNode = (Node*)malloc(sizeof(Node));
	if (pNewNode == NULL)
	{
		assert(0);
		return NULL;
	}
	pNewNode->_data = data;
	pNewNode->_pNext = NULL;
	return pNewNode;
}
void SListPushBack(SList *pl, SDataType data)//尾插
{
	Node *PNewNode = NULL;
	assert(pl);
	Node *Pcur = NULL;
	PNewNode = BuySListNode(data);
	Pcur = pl->pHead;//从头开始
	if (pl->pHead == NULL)//如果头结点为空,直接放入新结点
	{
		pl->pHead = PNewNode;
	}
	else
	{
		while (Pcur->_pNext)//只要一直存在下一个节点,则继续遍历
		{
			Pcur = Pcur->_pNext;
		}
		Pcur->_pNext = PNewNode;
	}
}
void SListPopBack(SList *pl)//尾删
{
	assert(pl);
	if (pl->pHead == NULL)
	{
		assert(0);
		return;
	}
	else if (pl->pHead->_pNext == NULL)
	{
		free(pl->pHead);
		pl->pHead = NULL;
	}
	else
	{
		Node *pPreNode = NULL;//前一个节点
		Node *pTailNode = pl->pHead;//尾结点
		while (pTailNode->_pNext)
		{
			pPreNode = pTailNode;
			pTailNode = pTailNode->_pNext;
		}
		free(pTailNode);
		pPreNode->_pNext = NULL;
	}
}
void SListPushFront(SList *pl, SDataType data)//头插
{
	Node *pNewNode = NULL;
	assert(pl);
	pNewNode = BuySListNode(data);
	pNewNode->_pNext = pl->pHead;
	pl->pHead = pNewNode;
}
void SListPopFront(SList *pl)//头删
{
	assert(pl);
	if (pl->pHead == NULL)
		return;
	else
	{
		Node *pDelNode = pl->pHead;
		pl->pHead = pDelNode->_pNext;
		free(pDelNode);
	}
}
Node* SListFind(SList *pl,SDataType data)
{
	assert(pl);
	Node *pCur = pl->pHead;
	while (pCur)
	{
		if (pCur->_data == data)
		{
			return pCur;
		}
		else
			pCur = pCur->_pNext;
	}
	return pCur;
}
void SListInsertAfter(Node *pos, SDataType data)//任意位置插入
{
	Node *pNewNode = NULL;
	if (pos == NULL)
		return;
	pNewNode = BuySListNode(data);
	pNewNode->_pNext = pos->_pNext;
	pos->_pNext = pNewNode;
}
void SListErase(SList *pl, Node *pos)//任意位置删除
{
	Node* pPreNode = NULL;
	assert(pl);
	if (pl->pHead==NULL||pos == NULL)
		return;
	if (pos==pl->pHead)//只有一个结点
	{
		pl->pHead = pos->_pNext;
		free(pos);
		return;
	}
	pPreNode = pl->pHead;
	while (pPreNode->_pNext != pos)
	{
		pPreNode = pPreNode->_pNext;
	}
	pPreNode->_pNext = pos->_pNext;
	free(pos);
}
int SListSize(SList *pl)//找寻节点个数
{
	Node *pCur = NULL;
	int count = 0;
	assert(pl);
	pCur = pl->pHead;
	while (pCur)
	{
		pCur = pCur->_pNext;
		count++;
	}
	return count;
}
SDataType SListFront(SList *pl)//获取第一个节点
{
	assert(pl);
	return pl->pHead->_data;
}
SDataType SListBack(SList *pl)//必须保证有尾结点,获取最后一个节点
{
	Node *pCur = NULL;
	assert(pl);
	pCur = pl->pHead;
	while (pCur->_pNext)
	{
		pCur = pCur->_pNext;
	}
	return pCur->_data;
}
void PrintSList(SList *pl)//显示
{
	Node *pCur = NULL;
	assert(pl);
	pCur = pl->pHead;
	while (pCur)
	{
		printf("%d---->", pCur->_data);
		pCur = pCur->_pNext;
	}
	printf("NULL\n");
}
void SListDestroy(SList *pl)
{
	Node* pCur = NULL;
	assert(pl);
	pCur = pl->pHead;
	while (pCur)
	{
		pl->pHead = pCur->_pNext;
		free(pCur);
		pCur = pl->pHead;
	}
	pl->pHead = NULL;
}
int SListEmpty(SList *pl)//置空
{
	assert(pl);
	return NULL == pl->pHead;
}
Node* ReverseSList(SList *pl)//逆置
{
	Node* p = NULL;
	Node* next = NULL;
	if (pl->PHead == NULL)
		return NULL;
	p = pl->PHead->_PNext;
	pl->PHead->_PNext = NULL;//将第一个结点后的结点置空
	while (p != NULL) {
		next = p->_PNext;
		p->_PNext = pl->PHead;
		pl->PHead = p;
		p = next;
	}
	return pl->PHead;
}
Node* removeElements1(SList *pl, SDataType val)//删除所有为val的值
{
	Node *pPreNode = NULL;
	Node *pCur = NULL;
	assert(pl);
	pPreNode = pl->pHead;
	pCur = pl->pHead->_pNext;
	if (pl->pHead == NULL)
		return NULL;
	while (pCur)
	{
		if (pCur->_data == val)
		{
			pPreNode->_pNext = pCur->_pNext;
		}
		else
		{
			pPreNode = pCur;
		}
		pCur = pCur->_pNext;
	}
	if (pl->pHead->_data == val)
	{
		return pl->pHead->_pNext;
	}
	else
		return pl->pHead;
}
Node *removeElements2(SList *pl, SDataType val)//删除所有为val的结点第二种方法
//遇到不等于val的就尾插到另一个链表中
{
	Node *ResultHead = NULL;//另一链表
	Node *cur = pl->pHead;
	Node *last = NULL;
	while (cur != NULL)
	{
		Node* next = cur->_pNext;
		if (cur->_data != val)
		{
			if (ResultHead == NULL)//如果结果链表为空,直接插入
			{
				ResultHead = cur;
			}
			else//尾插
			{
				cur->_pNext = NULL;
				last->_pNext = cur;
			}
			last = cur;
		}
		cur = next;
	}
	return ResultHead;
}

分析反转单链表:遍历链表,从第二个结点起,摘下每个结点,头插到原始链表中,将第一个节点后的结点销毁
删除所有值为val的值:有两种方法,第一种是在从第二个结点开始遍历,如果遇到要删除的值时,删除,让前一个结点指针指向它的下一个,如果没有遇到,前一个结点指针指向它,遍历下一个,最后判断第一个节点是否是要删除的值,如果是返回第二个节点,否则返回头一个节点;第二种方法是定义一个结果链表,用于保存值不等于val的结点,即遍历当遇到不等于val的就尾插到结果链表中。

  • 还有两种特殊情况
    1.不带头结点,也不用链表结构时应该用二级指针,例如实现尾插
void SListPushBack2(Node**PHead, SDataType data);//不用链表结构的尾插,不带头结点
void SListPushBack2(Node**PHead, SDataType data)//不用链表结构的尾插,不带头结点
{
	assert(PHead);
	Node *PNewNode = BuySListNode(data);
	if (NULL == *PHead)
	{
		*PHead = PNewNode;
	}
	else
	{
		Node *cur = NULL;
		cur=*PHead;
		while (cur->_PNext)
		{
			cur = cur->_PNext;
		}
		cur->_PNext = PNewNode;
	}
}

分析:因为在实现过程中,链表指针发生了改变,必须传链表地址,因此应该用二级指针来接收链表
2.带头节点的单链表,例如实现头插

void SListPushFront2(Node *NodeHead, SDataType data)//带头节点的头插
{
	assert(NodeHead);
	Node *PNewNode = BuySListNode(data);
	PNewNode->_PNext = NodeHead->_PNext;
	NodeHead->_PNext = PNewNode;
}

头结点为没有有效元素的结点,只要链表不为空,头结点一直存在

单链表的合并

源代码如下:

typedef struct ListNode
{
	int data;
	struct ListNode *next;
}Node;
Node* mergeTwoList(Node *s1, Node *s2)
{
	Node *ResultHead = NULL;
	Node *last = NULL;
	Node *c1 = s1;
	Node *c2 = s2;
	if (s1 == NULL)
		return s2;
	if (s2 == NULL)
		return s1;
	while (c1 != NULL&&c2 != NULL)
	{
		if (c1->data <= c2->data)
		{
			Node *next = c1->next;
			//将c1尾插到ResultHead
			c1->next = NULL;
			if (ResultHead == NULL)
			{
				ResultHead = c1;
			}
			else
			{
				last->next = c1;
			}
			last = c1;
			c1 = next;
		}
		else
		{
			Node *next = c2->next;
			//将c1尾插到ResultHead
			c2->next = NULL;
			if (ResultHead == NULL)
			{
				ResultHead = c2;
			}
			else
			{
				last->next = c2;
			}
			last = c2;
			c2 = next;
		}
	}
	if (c1 != NULL)
		last->next = c1;
	if (c2 != NULL)
		last->next=c2;
	return ResultHead;
}
Node* createList1()
{
	Node *n1 = (Node*)malloc(sizeof(Node));
	n1->data = 1;
	Node *n2 = (Node*)malloc(sizeof(Node));
	n2->data = 2;
	Node *n3 = (Node*)malloc(sizeof(Node));
	n3->data = 3;
	Node *n4 = (Node*)malloc(sizeof(Node));
	n4->data = 4;
	Node *n5 = (Node*)malloc(sizeof(Node));
	n5->data = 5;
	n1->next = n2;
	n2->next = n3;
	n3->next = n4;
	n4->next = n5;
	n5->next = NULL;
	return n1;
}
Node* createList2()
{
	Node *n1 = (Node*)malloc(sizeof(Node));
	n1->data = 1;
	Node *n2 = (Node*)malloc(sizeof(Node));
	n2->data = 3;
	Node *n3 = (Node*)malloc(sizeof(Node));
	n3->data = 5;
	Node *n4 = (Node*)malloc(sizeof(Node));
	n4->data = 7;
	n1->next = n2;
	n2->next = n3;
	n3->next = n4;
	n4->next = NULL;
	return n1;
}
int main()
{
	Node* cur = NULL;
	Node* PH1=createList1();
	Node* PH2=createList2();
	Node* Rhead=mergeTwoList(PH1, PH2);
	for (cur = Rhead; cur != NULL; cur = cur->next)
	{
		printf("%d ", cur->data);
	}
	printf("\n");
	system("pause");
	return 0;
}

分析:实现将两个有序链表,将两个链表合并后还是有序,定义一个结果链表,遍历两个链表,将值较小的先尾插到结果链表中,最后再判断哪个链表中还有没有剩余结点,若有,尾插到结果链表,返回结果链表。
源代码见:(github)
https://github.com/wangbiy/DS/tree/master/test_2019_6_28_1
附加:用C++实现源代码(学习C++与Linux后)(github)
https://github.com/wangbiy/review/tree/master/SList

链表例题

  • 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。
//编写代码,以给定值x为基准将链表分割成两部分,
//所有小于x的结点排在大于或等于x的结点之前 。
Node* partition(Node* head, int x)
{
	Node* small = NULL;
	Node* big = NULL;
	Node* smallLast = NULL;
	Node* bigLast = NULL;
	Node* cur = head;
	while (cur!=NULL)
	{
		Node* next = cur->next;
		if (cur->val < x)
			//尾插到small链表中
		{
			cur->next = NULL;
			if (small == NULL)
			{
				small = cur;
			}
			else
			{
				smallLast->next = cur;
			}
			smallLast = cur;//因为之前的最后一个结点是插入的,用smalllast记录
			cur = next;
		}
		else
		{
			cur->next = NULL;
			if (big == NULL)
			{
				big = cur;
			}
			else
			{
				bigLast->next = cur;
			}
			bigLast = cur;
			cur = next;
		}
	}
	if (small == NULL)
		return big;
	else
	{
		smallLast->next = big;
		return small;
	}
}

分析:定义两个链表,一个链表存放小于x的结点,一个链表存放大于等于x的结点,遍历原链表,将小于x的结点尾插到小链表中,将其他的结点尾插到大链表中,最后判断小链表是否为空,如果为空,直接返回大链表,不为空,将两个链表合并。

  • 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
    第一种方法:采用两个循环
/给定一个带有头结点 head 的非空单链表,
//返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
Node* MiddleNode(Node *head)
{
	assert(head);
	Node* cur = head;
	int size = 0;
	while (cur != NULL)
	{
		cur = cur->next;
		size++;
	}
	Node* p = head;
	for (int i = 0; i < size / 2; i++)
	{
		p = p->next;
	}
	return p;
}

分析:先求出链表的长度,定义一个指针,遍历链表的一半长度,返回指针所指的位置。
第二种方法:利用快慢指针方法

Node* MiddleNode2(Node *head)
{
	Node* fast = head;
	Node* slow = head;
	while (fast != NULL)
	{
		fast = fast->next;
		if (fast == NULL)
			break;
		slow = slow->next;
		fast = fast->next;
	}
	return slow;
}

  • 输入一个链表,输出该链表中倒数第k个结点。
    第一种方法,实现两次遍历
//输入一个链表,输出该链表中倒数第k个结点。
Node* FindkToTail(Node* head, unsigned int k)
{
	Node* cur = NULL;
	assert(head);
	cur = head;
	int size = 0;
	while (cur != NULL)
	{
		cur = cur->next;
		size++;
	}
	if (size < k)
		return NULL;
	else
	{
		Node* p = head;
		for (int i = 0; i < size - k; i++)
		{
			p = p->next;
		}
		return p;
	}
}

分析:__先求出链表长度,如果链表长度小于k,直接返回NULL,否则定义一个指针,从头遍历到长度size-k,这个指针指向的就为k的位置,返回这个指针所指的位置。
第二种方法:运用前后指针

Node* FindkToTail2(Node* head, unsigned int k)
{
	assert(head);
	Node* front = head;
	Node* back = head;
	for (int i = 0; i < k; i++)
	{
		if (front == NULL)
			return NULL;
		front = front->next;
	}
	while (front != NULL)
	{
		front = front->next;
		back = back->next;
	}
	return back;
}

分析:定义两个指针指向第一个节点,第一个指针先遍历k个,然后两个指针一起向后走,直到第一个指针到NULL,第二个指针就走了size-k长度,那么第二个指针指向的位置就为倒数第k个位置。

  • 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针
    第一种方法:构造一个假结点为了使每个节点都有前驱来进行删除
Node* DeleteDupLication1(Node* head)
{
	Node* fackNode=(Node*)malloc(sizeof(Node));//构造一个假结点,因为要考虑第一个结点就是重复的
	fackNode->next = head;
	Node* pre = fackNode;
	Node* p1 = head;
	Node* p2 = head->next;
	if (head == NULL)
		return NULL;
	while (p2 != NULL)//p2等于空时结束
	{
		if (p1->val != p2->val)
		{
			pre = p1;
			p1 = p1->next;
			p2 = p2->next;
		}
		else
		{
			while (p2 != NULL&&p2->val == p1->val)
			{
				p2 = p2->next;
			}
			//删除p1到p2之间所有的节点
			pre->next = p2;
			p1 = p2;
			if (p2 != NULL)
			{
				p2 = p2->next;
			}
		}
	}
	return fackNode->next;
}

分析:定义三个指针,一个前驱指针pre,p1,p2,pre指向构造的假结点,p1指向第一个节点,p2指向第二个节点,如果链表为空,返回NULL,当结点不重复时,三个指针都往后走,一直到出现重复的节点或p2为空时;当出现重复的节点时,p2往后走,直到p2为空或者P1到p2之间出现不同的结点时,删除p1到p2之间所有的节点,让pre的下一个指向p2,p1指向p2,如果这时p2不为空,p2指向它的下一个。
第二种方法是当从第一开始重复的时候,pre为空,将head到达p2的位置,pre不为空时,不重复,pre的下一个指向p2。

Node* DeleteDupLication2(Node* head)
{
	Node* pre = NULL;
	Node* p1 = head;
	Node* p2 = head->next;
	if (head == NULL)
		return NULL;
	while (p2 != NULL)//p2等于空时结束
	{
		if (p1->val != p2->val)
		{
			pre = p1;
			p1 = p1->next;
			p2 = p2->next;
		}
		else
		{
			while (p2 != NULL&&p2->val == p1->val)
			{
				p2 = p2->next;
			}
			//删除p1到p2之间所有的节点
			if (pre != NULL)
			{
				pre->next = p2;
				
			}
			else
			{
				head = p2;
			}
			p1 = p2;
			if (p2 != NULL)
			{
				p2 = p2->next;
			}
		}
	}
	return head;
}

若重复的结点保留一个,则去掉pre指针。

  • 判断链表是否为回文结构
//判断链表是否为回文结构
Node* FindMiddle(Node* head)
{
	Node* fast = head;
	Node* slow = head;
	while (fast != NULL)
	{
		fast = fast->next;
		if (fast == NULL)
			break;
		slow = slow->next;
		fast = fast->next;
	}
	return slow;
}
Node* reverse(Node* head)
    {
        if(head==NULL)
            return NULL;
        Node* p=head->next;
        head->next=NULL;
        while(p!=NULL)
        {
            Node* next=p->next;
            p->next=head;
            head=p;
            p=next;
        }
        return head;
    }
void checkHuiwen(Node* head)
{
	Node* middle = FindMiddle(head);
	Node* result = reverseSList(middle);
	Node* c1 = head;
	Node* c2 = result;
	while (c1 != NULL&&c2 != NULL)
	{
		if (c1->val != c2->val)
		{
			printf("不是回文结构!\n");
		}
		c1 = c1->next;
		c2 = c2->next;
	}
	printf("是回文结构!\n");
}

分析:要判断链表是否为回文结构,首先要知道链表的中间节点,然后从中间节点开始的结点逆置,遍历两个链表,进行比较,若相同,则为回文结构,否则不是。

  • 在两个链表中找第一个公共结点,公共结点后的链表是相同的。
int GetLength(Node* head)
{
	Node* cur = NULL;
	int length = 0;
	cur = head;
	while (cur != NULL)
	{
		cur = cur->next;
		length++;
	}
	return length;
}
Node* publicNode(Node* head1, Node* head2)
{
	Node* longer = head1;
	Node* shorter = head2;
	int length1 = GetLength(head1);
	int length2 = GetLength(head2);
	int diff = length1 - length2;
	if (length2 > length1)
	{
		longer = head2;
		shorter = head1;
		diff = length2 - length1;
	}
	for (int i = 0; i < diff; i++)
	{
		longer = longer->next;
	}
	while (shorter&&longer != shorter)
	{
		longer = longer->next;
		shorter = shorter->next;
	}
	return longer;
}

分析:两个链表不一定一样长,先计算出两个链表的长度,计算出长度差,定义两个指针,其中一个指针让它从长链表开始遍历长度差个长度,然后两个指针一起往后走,直到遇到空或者找到公共点。

  • 给定一个链表,返回链表开始入环的第一个节点,如果链表无环,则返回NULL
Node* hascycle(Node* head)
{
	//判断是否有环,利用快慢指针找相遇点
	Node* fast = head;
	Node* slow = head;
	if (head == NULL)
		return NULL;
	do
	{
		fast = fast->next;
		if (fast == NULL)
			return NULL;
		fast = fast->next;
		if (fast == NULL)
			return NULL;
		slow = slow->next;
	} while (fast != slow);//fast或者slow都为相遇点
	//找环的入口点
	//一个指针从起点出发,一个指针从相遇点出发,各自走一步,一定会相遇在环的入口点
	Node* p1 = head;
	Node* p2 = slow;
	while (p1 != p2)
	{
		p1 = p1->next;
		p2 = p2->next;
	}
	return p1;
}

分析:首先判断链表是否有环,利用快慢指针,定义两个指针,一个先走两步,一个再走一步,直到两个指针相遇,则有环,然后找环的入口点,一个指针从起点出发,一个指针从相遇点出发,各自走一步,一定会相遇在环的入口点,证明如下图
在这里插入图片描述

  • 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何结点或空节点,要求返回这个链表的深度拷贝
Node* copyRandomList(Node* head) {
        if(head==NULL)
            return NULL;
        Node* cur=head;
        
        //赋值
        while(cur!=NULL)
        {
            Node* node=(Node*)malloc(sizeof(Node));
            node->val=cur->val;
            node->next=cur->next;
            cur->next=node;
            cur=node->next;
        }
        //进行random操作
        cur=head;
        while(cur!=NULL&&cur->next!=NULL)
        {
            if(cur->random==NULL)
            {
                cur->next->random=NULL;
            }
            else
            {
                cur->next->random=cur->random->next;
            }
            cur=cur->next->next;
        }
        cur=head;
        Node* pNewNode=head->next;
        while(cur!=NULL&&cur->next!=NULL)
        {
            Node* node=cur->next;
            cur->next=node->next;
            if(node->next!=NULL)
            {
                node->next=node->next->next;
            }
            cur=cur->next;
        }
        return pNewNode;      
    }

分析:首先先复制一份链表每个节点的值,在将第二个链表的值放在与原链表相同的值后面,例如,原链表为1 2 3 4 NULL,1的random指针指向2,2的random指针指向1,3的random指针指向自己,4的random指针指向NULL,则操作后的链表为1 1 2 2 3 3 4 4 NULL,之后遍历链表,如果结点的random指针等于空,则这个节点的下一个结点的random指针为NULL,否则,这个节点的下一个结点的random指针指向这个节点的random指针指向的结点的下一个,即4的下一个节点4的random指向NULL,1的下一个节点1的random指向2,2的下一个节点2的random指针指向1,3的下一个节点3的random指针指向3,一次遍历两个结点;然后拆开链表,从头开始遍历操作后的链表,将复制后的结点取出来,返回新链表。

©️2020 CSDN 皮肤主题: 黑客帝国 设计师: 上身试试 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值