<Lista enlazada única> Ejercicio "Estructura de datos (versión en lenguaje C)"

Tabla de contenido

tema:

【Pregunta de programación】

1. Adición, supresión y modificación de la lista de enlace simple

2. Eliminar el enlace DO del elemento de la lista enlazada

3. Invierta una lista enlazada individualmente. enlace DO

4. El nodo medio de la lista enlazada

5. El k-ésimo nodo desde abajo en la lista enlazada

6. Combinar dos matrices ordenadas

7. Segmentación de listas enlazadas CM11

8. Estructura palindrómica de lista enlazada. enlace DO

9. Intersección de la lista enlazada OJ link

10. Lista circular enlazada II

12. Copie la lista enlazada con punteros aleatorios

Analizar gramaticalmente:

Posdata: ●Debido al nivel limitado del autor, el artículo inevitablemente contendrá errores, por favor, lectores para corregir, jerga en artículos, ¡esperamos sinceramente un consejo!

                                                                                           —— Por autor: Xinxiao Guzhi


tema:

【Pregunta de programación】

1. Adición, supresión y modificación de la lista de enlace simple

2. Eliminar el  enlace DO del elemento de la lista enlazada

3. Invierta una lista enlazada individualmente. enlace DO

4. El nodo medio de la lista enlazada

Dada una lista no vacía con un solo enlace con el encabezado del nodo principal, devuelve el nodo medio de la lista enlazada. Si hay dos nodos intermedios, devuelva el segundo nodo intermedio. enlace DO 

5. El k-ésimo nodo desde abajo en la lista enlazada

Ingrese una lista vinculada y genere el k-ésimo nodo desde la parte inferior de la lista vinculada. enlace DO

6. Combinar dos matrices ordenadas

Combinar dos listas vinculadas ordenadas en una nueva lista vinculada ordenada y regresar. La nueva lista enlazada se forma empalmando todos los nodos de las dos listas enlazadas dadas. enlace DO

7. Segmentación de listas enlazadas CM11

Escriba código para dividir la lista vinculada en dos partes en función de un valor dado x, y todos los nodos menores que x se ordenan antes que los nodos mayores o iguales a x. enlace DO

8. Estructura palindrómica de lista enlazada. enlace DO

9. Intersección de la lista enlazada OJ link

 

10. Lista circular enlazada II

Dada una lista enlazada, devuelve el primer nodo donde la lista enlazada comienza a entrar en el anillo. Si la lista enlazada no tiene bucle, devuelve el  enlace NULL OJ

11. Lista circular enlazada I

Dada una lista enlazada, determine si hay un ciclo en la lista enlazada. enlace DO

12. Copie la lista enlazada con punteros aleatorios

Dada una lista enlazada, cada nodo contiene un puntero aleatorio adicional que puede apuntar a cualquier nodo de la lista enlazada o a un nodo vacío. Solicitudes para devolver una copia profunda de esta lista vinculada. enlace DO enlace DO

 

Analizar gramaticalmente:

 1. 

// SeqList.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
 
typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity; // unsigned int
}SeqList;
 
// 对数据的管理:增删查改 
void SeqListInit(SeqList* ps);
void SeqListDestory(SeqList* ps);
 
void SeqListPrint(SeqList* ps);
void SeqListPushBack(SeqList* ps, SLDateType x);
void SeqListPushFront(SeqList* ps, SLDateType x);
void SeqListPopFront(SeqList* ps);
void SeqListPopBack(SeqList* ps);
 
// 顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, size_t pos, SLDateType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, size_t pos);
// slist.c
#include "SList.h"
 
 
SListNode* BuySListNode(SLTDateType x)
{
	SListNode* node = (SListNode*)malloc(sizeof(SListNode));
	node->data = x;
	node->next = NULL;
 
	return node;
}
 
void SListPrint(SListNode* plist)
{
	SListNode* cur = plist;
	while (cur)
	//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 != NULL)
		{
			tail = tail->next;
		}
 
		tail->next = newnode;
	}
}
 
void SListPopBack(SListNode** pplist)
{
	SListNode* prev = NULL;
	SListNode* tail = *pplist;
	// 1.空、只有一个节点
	// 2.两个及以上的节点
	if (tail == NULL || tail->next == NULL)
	{
		free(tail);
		*pplist = NULL;
	}
	else
	{
		while (tail->next)
		{
			prev = tail;
			tail = tail->next;
		}
 
		free(tail);
		tail = NULL;
 
		prev->next = NULL;
	}
}
 
 
void SListPushFront(SListNode** pplist, SLTDateType x)
{
	assert(pplist);
 
	// 1.空
	// 2.非空
	SListNode* newnode = BuySListNode(x);
	if (*pplist == NULL)
	{
		*pplist = newnode;
	}
	else
	{
		newnode->next = *pplist;
		*pplist = newnode;
	}
}
 
void SListPopFront(SListNode** pplist)
{
	// 1.空
	// 2.一个
	// 3.两个及以上
	SListNode* first = *pplist;
	if (first == NULL)
	{
		return;
	}
	else if (first->next == NULL)
	{
		free(first);
		*pplist = NULL;
	}
	else
	{
		SListNode* next = first->next;
		free(first);
		*pplist = next;
	}
}
 
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	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* next = pos->next;
	// pos newnode next
	SListNode* newnode = BuySListNode(x);
	pos->next = newnode;
	newnode->next = next;
}
 
void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	// pos next nextnext
	SListNode* next = pos->next;
 
	if (next != NULL)
	{
		SListNode* nextnext = next->next;
		free(next);
		pos->next = nextnext;
	}
}

 2.

Solución 1:

/*
解题思路:从头节点开始进行元素删除,每删除一个元素,需要重新链接节点
*/
struct ListNode* removeElements(struct ListNode* head, int val) {
    if(head == NULL)
        return NULL;
    
    struct ListNode* cur = head;
    struct ListNode* prev = NULL;
    
    while(cur)
    {
        //如果当前节点是需要删除的节点
        if(cur->val == val)
        {
            //首先保存下一个节点
            struct ListNode* next = cur->next;
            //如果删除的为头节点,更新头节点
            //否则让当前节点的前趋节点链接next节点
            if(prev == NULL)
            {
                head = cur->next;
            }
            else
            {
                prev->next = cur->next;  
            }
            //释放当前节点,让cur指向next
            free(cur);
            cur = next;
        }
        else
        {
            //如果cur不是需要删除的节点,则更新prev,cur
            prev = cur;
            cur = cur->next;
        }
    }
    
    return head;
}

Solución 2:

struct ListNode* removeElements(struct ListNode* head, int val)
{
	struct ListNode* prev = NULL;
	struct ListNode* cur = head;
	while (cur)
	{
		if (cur->val != val)
		{
			prev = cur;
			cur = cur->next;
		}
		else
		{
			struct ListNode* next = cur->next;
			if (prev == NULL)
			{
				free(cur);
				head = next;
				cur = next;
			}
			else
			{
				free(cur);
				prev->next = next;
				cur = next;
			}
		}
	}
	return head;
}

3. 

Solución 1:

/*
解题思路: 此题一般常用的方法有两种,三指针翻转法和头插法
1. 三指针翻转法
   记录连续的三个节点,原地修改节点指向
2. 头插法
   每一个节点都进行头插
*/
// 三个指针翻转的思想完成逆置
struct ListNode* reverseList(struct ListNode* head) {
    if(head == NULL || head->next == NULL)
        return head;
    
    struct ListNode* n1, *n2, *n3;
    n1 = head;
    n2 = n1->next;
    n3 = n2->next;
    n1->next = NULL;
    //中间节点不为空,继续修改指向
    while(n2)
    {
        //中间节点指向反转
        n2->next = n1;
        //更新三个连续的节点
        n1 = n2;
        n2 = n3;
        if(n3)
            n3 = n3->next;
    }
    //返回新的头
    return n1;
}
 
// 取节点头插的思想完成逆置
struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* newhead = NULL;
    struct ListNode* cur = head;
    while(cur)
    {
        struct ListNode* next = cur->next;
        //头插新节点,更新头
        cur->next = newhead;
        newhead = cur;
        cur = next;
    }
    
    return newhead;
}

 Solución 2:

struct ListNode* reverseList(struct ListNode* head)
{
	struct ListNode* newHead = NULL;
	struct ListNode* cur = head;
	while (cur)
	{
		struct ListNode* next = cur->next;
		//头插
		cur->next = newHead;
		newHead = cur;


		cur = next;
	}
	return newHead;
}

4.

Solución 1:

/*
解题思路:
通过快慢指针找到中间节点,快指针每次走两步,慢指针每次走一步,当快指针走到结尾的时候,慢指针正好走到中间位置
*/
typedef struct ListNode Node;
struct ListNode* middleNode(struct ListNode* head){
    Node* slow = head;
    Node* fast = head;
 
    while(fast!=NULL && fast->next != NULL)
    {
       slow = slow->next;
       fast = fast->next->next;
    }
 
    return slow;
}

Solución 2:

struct ListNode* middleNode(struct ListNode* head) 
{
	struct ListNode* slow, * fast;
	slow = fast = head;
	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;
	}
	return slow;
}

5.

Solución 1:

/*
解题思路:
快慢指针法 fast, slow, 首先让fast先走k步,然后fast,slow同时走,fast走到末尾时,slow走到倒数第k个节点。
*/
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        struct ListNode* slow = pListHead;
        struct ListNode* fast = slow;
        while(k--)
        {
            if(fast)
                fast = fast->next;
            else
                return NULL;
        }
         
        while(fast)
        {
            slow = slow->next;
            fast = fast->next;
        }
         
        return slow;
    }
};

Solución 2:

//1.链表中倒数第k个结点
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k) 
{
    struct ListNode* slow, * fast;
    slow = fast = pListHead;
    //fast先走k步
    while (k--)
    {
        //k大于链表的长度
        if (fast == NULL)
        {
            return NULL;
        }
        fast = fast->next;
    }
    while (fast)
    {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

6.

Solución 1:

/*
解题思路:
此题可以先创建一个空链表,然后依次从两个有序链表中选取最小的进行尾插操作进行合并。
*/
typedef struct ListNode Node;
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
        if(l1 == NULL)
            return l2;
        else if(l2 == NULL)
           return l1;
             
        Node* head = NULL, *tail = NULL;
        //创建空链表
    	head = tail = (Node*)malloc(sizeof(Node));
        tail->next = NULL;
        while(l1 && l2)
        {
            // 取小的进行尾插
            if(l1->val < l2->val)
            {
                tail->next = l1;
                tail = tail->next;
 
                l1 = l1->next;
            }
            else
            {
                tail->next = l2;
                tail = tail->next;
 
                l2 = l2->next;
            }
        }
        //剩余元素直接拼接
        if(l1)
            tail->next = l1;
        else
            tail->next = l2;
 
        Node* list = head->next;
        free(head);
        return list;
}

Solución 2:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{   //尾插法
	if (list1 == NULL)
	{
		return list2;
	}
	if (list2== NULL)
	{
		return list1;
	}
	struct ListNode* head = NULL, * tail = NULL;
	while (list1 && list2)
	{
		if (list1->val < list2->val)
		{   //head和tail最初都是空指针
			if (tail == NULL)
			{
				head = tail = list1;
			}
			else
			{
				tail->next = list1;
				tail = list1;
			}
			list1 = list1->next;
		}
		else
		{
			if (tail == NULL)
			{
				head = tail = list2;
			}
			else
			{
				tail->next = list2;
				tail = list2;
			}
			list2 = list2->next;
		}
	}
	if (list1)
	{
		tail->next = list1;
	}
	if (list2)
	{
		tail->next = list2;
	}
	return head;
}

7.

Solución 1:

/*
解题思路
创建两个链表,分别存放小于x的节点和大于等于x的节点,分别进行尾插
*/
class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        if(pHead == NULL)
            return NULL;
        
        struct ListNode* lessHead, *lessTail,*greaterHead, *greaterTail;
        //创建链表表头
        lessHead = lessTail = (struct ListNode*)malloc(sizeof(struct ListNode));
        greaterHead = greaterTail = (struct ListNode*)malloc(sizeof(struct ListNode));
        struct ListNode* cur = pHead;
        while(cur)
        {
            //小于x的尾插到lessTail
            if(cur->val < x)
            {
                lessTail->next = cur;
                lessTail = lessTail->next;
            }
            //大于等于x的尾插到greaterTail
            else
            {
                greaterTail->next = cur;
                greaterTail = greaterTail->next;
            }
            cur = cur->next;
        }
        //链接两个链表
        lessTail->next = greaterHead->next;
        greaterTail->next = NULL;
        //获取表头
        pHead = lessHead->next;
        free(lessHead);
        free(greaterHead);
        
        return pHead;
    }
};

Solución 2:

//2.链表分割—C语言实现
class Partition 
{
public:
    ListNode* partition(ListNode* pHead, int x)
    {
        struct ListNode* lessHead, * lessTail, * greaterHead, * greaterTail;
        lessHead = lessTail = (struct ListNode*)malloc(sizeof(struct ListNode));
        greaterHead = greaterTail = (struct ListNode*)malloc(sizeof(struct ListNode));


        lessTail->next = greaterTail->next = NULL;
        
        struct ListNode* cur = pHead;
        while (cur)
        {
            if (cur->val < x)
            {
                lessTail->next = cur;
                lessTail = lessTail->next;
            }
            else
            {
                greaterTail->next = cur;
                greaterTail = greaterTail->next;
            }
            cur = cur->next;
        }
        lessTail->next = greaterHead->next;
        greaterTail->next = NULL;
        struct ListNode* list = lessHead->next;
        free(lessHead);   //lessHead=NULL;
        free(greaterHead); //greaterHead=NULL;
        return list;
    }
};

8.

/*
解题思路:
此题可以先找到中间节点,然后把后半部分逆置,最近前后两部分一一比对,如果节点的值全部相同,则即为回文。
*/
class PalindromeList {
public:
	bool chkPalindrome(ListNode* A) {
		if (A == NULL || A->next == NULL)
			return true;
		ListNode* slow, *fast, *prev, *cur, *nxt;
		slow = fast = A;
		//找到中间节点
		while (fast && fast->next)
		{
			slow = slow->next;
			fast = fast->next->next;
		}
		prev = NULL;
		//后半部分逆置
		cur = slow;
		while (cur)
		{
			nxt = cur->next;
			cur->next = prev;
			prev = cur;
			cur = nxt;
		}
		//逐点比对
		while (A && prev)
		{
			if (A->val != prev->val)
				return false;
			A = A->next;
			prev = prev->next;
		}
		return true;
	}
};
/*
此题也可以先把链表中的元素值全部保存到数组中,然后再判断数组是否为回文。不建议使用这种解法,因为如果没有告诉链表最大长度,则不能同此解法
*/
class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        // write code here
        int a[900] = {0};
        ListNode* cur = A;
        int n = 0;
        //保存链表元素
        while(cur)
        {
            a[n++] = cur->val;
            cur = cur->next;
        }
        //判断数组是否为回文结构
        int begin = 0, end = n-1;
        while(begin < end)
        {
            if(a[begin] != a[end])
                return false;
            ++begin;
            --end;
        }
         
        return true;
    }
};

9.

/*
解题思路:
此题可以先计算出两个链表的长度,让长的链表先走相差的长度,然后两个链表同时走,直到遇到相同的节点,即为第一个公共节点
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int lenA = 0, lenB = 0;
    struct ListNode* curA = headA, *curB = headB;
    //计算链表长度
    while(curA) {
        ++lenA;
        curA = curA->next;
    }
    
    while(curB) {
        ++lenB;
        curB = curB->next;
    }
    
    int gap = abs(lenA-lenB);
    struct ListNode* longList = headA, *shortList = headB;
    if(lenA < lenB) {
        longList = headB;
        shortList = headA;
    }
    //让长链表先走几步
    while(gap--){
        longList = longList->next;
    }
    //两个链表同时走,直到遇到相同的节点
    while(longList && shortList)
    {
        if(longList == shortList) {
            return longList;
        }
        else {
            longList = longList->next;
            shortList = shortList->next;
        }
    }
    
    return NULL;
}

10

/*
解题思路:
如果链表存在环,则fast和slow会在环内相遇,定义相遇点到入口点的距离为X,定义环的长度为C,定义头到入口的距离为L,fast在slow进入环之后一圈内追上slow,则会得知:
slow所走的步数为:L + X
fast所走的步数为:L + X + N * C
并且fast所走的步数为slow的两倍,故:
2*(L + X) = L + X + N * C
即: L = N * C - X
所以从相遇点开始slow继续走,让一个指针从头开始走,相遇点即为入口节点
*/
typedef struct ListNode Node;
struct ListNode *detectCycle(struct ListNode *head) {
    	Node* slow = head;
        Node* fast = head;
 
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
            //走到相遇点
            if(slow == fast)
            {
                // 求环的入口点
                Node* meet = slow;
                Node* start = head;
 
                while(meet != start)
                {
                    meet = meet->next;
                    start = start->next;
                }
 
                return meet;
            }
        }
 
        return NULL;
}

11

/*
解题思路:
定义快慢指针fast,slow, 如果链表确实有环,fast指针一定会在环内追上slow指针。
*/
typedef struct ListNode Node;
bool hasCycle(struct ListNode *head) {
   Node* slow = head;
   Node* fast = head;
 
  while(fast && fast->next)
  {
    slow = slow->next;
    fast = fast->next->next;
 
    if(slow == fast)
      return true;
  }
 
  return false;
}

12

/*
解题思路:
此题可以分三步进行:
1.拷贝链表的每一个节点,拷贝的节点先链接到被拷贝节点的后面
2.复制随机指针的链接:拷贝节点的随机指针指向被拷贝节点随机指针的下一个位置
3.拆解链表,把拷贝的链表从原链表中拆解出来
*/
class Solution {
public:
    Node* copyRandomList(Node* head) {
        // 1.拷贝链表,并插入到原节点的后面
        Node* cur = head;
        while(cur)
        {
            Node* next = cur->next;
 
            Node* copy = (Node*)malloc(sizeof(Node));
            copy->val = cur->val;
 
            // 插入
            cur->next = copy;
            copy->next = next;
 
            // 迭代往下走
            cur = next;
        }
 
        // 2.置拷贝节点的random
        cur = head;
        while(cur)
        {
            Node* copy = cur->next;
            if(cur->random != NULL)
                copy->random = cur->random->next;
            else
                copy->random = NULL;
 
            cur = copy->next;
        }
 
        // 3.解拷贝节点,链接拷贝节点
        Node* copyHead = NULL, *copyTail = NULL;
        cur = head;
        while(cur)
        {
            Node* copy = cur->next;
            Node* next = copy->next;
 
            // copy解下来尾插
            if(copyTail == NULL)
            {
                copyHead = copyTail = copy;
            }
            else
            {   
                copyTail->next = copy;
                copyTail = copy;
            }
 
            cur->next = next;
 
            cur = next;
        }
 
        return copyHead;
    }
};

Posdata:
●Debido al nivel limitado del autor, el artículo inevitablemente contendrá errores, por favor, lectores para corregir, jerga en artículos, ¡esperamos sinceramente un consejo!

                                                                                           —— Por autor: Xinxiao Guzhi

Supongo que te gusta

Origin blog.csdn.net/m0_57859086/article/details/124048954
Recomendado
Clasificación