终结Linked List(二)

三、编码技巧

1、遍历链表
先将head指针赋值给一个局部变量current

//return the number of nodes in a list (while-loop version)
int Length(struct node* head)
{
    int count = 0;
    struct node* current = head;

    while (current != NULL)
    {
        count++;
        current = current->next;
    }

    return count;
}

当然也可以写为:

for (current = head; current != NULL; current = current->next) {}

2、通过传递reference pointer改变某个指针
看个例子:

//Change the passed in head pointer to be NULL
//Uses a reference pointer to access the caller's memory
void ChangeToNull(struct node** headRef)  //takes a pointer to the value of interest
{
    *headRef = NULL;    //use * to access the value of interest
}

void ChangeCaller()
{
    struct node* head1;
    struct node* head2;

    ChangeToNull(&head1);   //use & to compute and pass a pointer to
    ChangeToNull(&head2);   //the value of interest
    //head1 and head2 are NULL at this point
}

这块的思想是和(一)中的Push()类似。
内存示意图:

3、通过Push()建立链表(头插法)
这种方式的优点是速度飞快,简单易行,缺点是得到的链表是逆序的:

struct node* AddAtHead()
{
    struct node* head = NULL;

    for (int i = 1; i < 6; i++)
    {
        Push(&head, i);
    }

    //head == {5,4,3,2,1};
    return head;
}

4、尾插法建立链表
这种方法需要找到链表最后一个节点,改变其.next域:

  • 插入或者删除节点,需要找到该节点的前一个节点的指针,改变其.next域;
  • 特例:如果涉及第一个节点的操作,那么一定要改变head指针。

5、特例+尾插法
如果要构建一个新的链表,那么头节点就要单独处理:

struct node* BuildWithSpecialCase()
{
    struct node* head = NULL;
    struct node* tail;

    //deal with the head node here, and set the tail pointer
    Push(&head, 1);
    tail = head;

    //do all the other nodes using "tail"
    for (int i = 2; i < 6; i++)
    {
        Push(&(tail->next), i);   //add node at tail->next
        tail = tail->next;     //advance tail to point to last node
    }

    return head;    //head == {1,2,3,4,5}
}

6、临时节点建立

struct node* BuildWithDummyNode()
{
    struct node dummy;   //dummy node is temporarily the first node
    struct node* tail = &dummy;   //build the list on dummy.next

    dummy.next = NULL;

    for (int i = 1; i < 6; i++)
    {
        Push(&(tail->next), i);
        tail = tail->next;
    }

    //the real result list is now in dummy.next
    //dummy.next == {1,2,3,4,5}
    return dummy.next;
}

7、本地指针建立

struct node* BuildWithLocalRef()
{
    struct node* head = NULL;
    struct node** lastPtrRef = &head;   //start out pointing to the head pointer

    for (int i = 1; i < 6; i++)
    {
        Push(lastPtrRef, i);  //add node at the last pointer in the list
        //advance to point to the new last pointer
        lastPtrRef = &((*lastPtrRef)->next);
    }

    return head;  //head == {1,2,3,4,5}
}

这块可能有些抽象:
1)lastPtrRef开始指向head指针,以后指向链表最后一个节点中的.next域;
2)在最后加上一个节点;
3)让lastPtrRef指针向后移动,指向最后一个节点的.next(*lastPtrRef)->next可以理解为*lastPtrRef指针指向的节点的next域。

四、代码示例

1、AppendNode()
1) 不使用Push()函数:

struct node* AppendNode(struct node** headRef, int num)
{
    struct node* current = *headRef;
    struct node* newNode;

    newNode = (struct node*)malloc(sizeof(struct node));
    newNode->data = num;
    newNode->next = NULL;

    //special case for length 0
    if (current == NULL)
    {
        *headRef = newNode;
    }
    else
    {
        //Locate the last node
        while (current->next != NULL)
        {
            current = current->next;
        }

        current->next = newNode;
    }
}

2) 使用Push()函数:

struct node* AppendNode(struct node** headRef, int num)
{
    struct node* current = *headRef;

    //special case for length 0
    if (current == NULL)
    {
        Push(headRef, num);
    }
    else
    {
        //Locate the last node
        while (current->next != NULL)
        {
            current = current->next;
        }

        //Build the node after the last node
        Push(&(current->next), num);
    }
}

2、CopyList
用一个指针遍历原来的链表,两个指针跟踪新生成的链表(一个head,一个tail)。

1) 不使用Push()函数:

struct node* CopyList(struct node* head)
{
    struct node* current = head;   //used to iterate over the original list
    struct node* newList = NULL;   //head of the new list
    struct node* tail = NULL;     //kept pointing to the last node in the new list

    while (current != NULL)
    {
        if (newList == NULL)    //special case for the first new node
        {
            newList = (struct node*)malloc(sizeof(struct node));
            newList->data = current->data;
            newList->next = NULL;
            tail = newList;
        }
        else
        {
            tail->next = (struct node*)malloc(sizeof(struct node));
            tail = tail->next;
            tail->data = current->data;
            tail->next = NULL;
        }
        current = current->next;
    }

    return newList;
}

内存示意图:

2) 使用Push()函数:

struct node* CopyList2(struct node* head)
{
    struct node* current = head;   //used to iterate over the original list
    struct node* newList = NULL;   //head of the new list
    struct node* tail = NULL;     //kept pointing to the last node in the new list

    while (current != NULL)
    {
        if (newList == NULL)    //special case for the first new node
        {
            Push(&newList, current->data);
            tail = newList;
        }
        else
        {
            Push(&(tail->next), current->data);   //add each node at the tail
            tail = tail->next;       //advance the tail to the new last node;
        }
        current = current->next;
    }

    return newList;
}

3) 使用Dummy Node

struct node* CopyList3(struct node* head)
{
    struct node* current = head;   //used to iterate over the original list
    struct node* tail = NULL;     //kept pointing to the last node in the new list
    struct node dummy;            //build the new list off this dummy node

    dummy.next = NULL;
    tail = &dummy;      //start the tail pointing at the dummy

    while (current != NULL)
    {
        Push(&(tail->next), current->data);   //add each node at the tail
        tail = tail->next;                    //advance the tail to the new last node
        current = current->next;
    }

    return dummy.next;
}

4) 使用Local References

struct node* CopyList4(struct node* head)
{
    struct node* current = head;   //used to iterate over the original list
    struct node* newList = NULL;   //head of the new list
    struct node** lastPtr;           

    lastPtr = &newList;      //start off pointing to the head itself

    while (current != NULL)
    {
        Push(lastPtr, current->data);   //add each node at the lastPtr
        lastPtr = &((*lastPtr)->next);    //advance lastPtr
        current = current->next;
    }

    return newList;
}

核心思想是使用lastPtr指针指向每个节点的.next域这个指针,而不是指向节点本身。

  1. 使用Recursive
struct node* CopyList5(struct node* head)
{
    struct node* current = head;
    if (head == NULL)
        return NULL;
    else {
        struct node* newList = (struct node*)malloc(sizeof(struct node));  //make one node
        newList->data = current->data;

        newList->next = CopyList5(current->next);    //recur for the rest
        return newList;
    }
}

原文地址:https://www.cnblogs.com/EIMadrigal/p/12130892.html

时间: 2024-10-11 17:08:45

终结Linked List(二)的相关文章

终结Linked List(三)

第一篇终结Linked List(一).终结Linked List(二)主要讲了单链表的基础知识,接下来的第二篇主要讲一些比较经典的问题. 一.Count() 给一个单链表和一个整数,返回这个整数在链表中出现了多少次. /* Given a list and an int, return the number of times that int ocucurs in the list. */ int Count(struct node* head,int searchFor) { int cnt

终结Linked List(一)

链表一直是面试的重点问题,恰好最近看到了Stanford的一篇材料,涵盖了链表的基础知识以及派生的各种问题. 第一篇主要是关于链表的基础知识. 一.基本结构 1.数组回顾 链表和数组都是用来存储一堆数据的集合,其中单个元素的类型可以有很多种. 通过数组下标可以直接访问数组中的元素,比如: void ArrayTest() { int scores[100]; //初始化前3个元素 scores[0] = 1; scores[1] = 2; scores[2] = 3; } 最关键的是:整个数组被

[leetcode]426. Convert Binary Search Tree to Sorted Doubly Linked List二叉搜索树转有序双向链表

Convert a BST to a sorted circular doubly-linked list in-place. Think of the left and right pointers as synonymous to the previous and next pointers in a doubly-linked list. Let's take the following BST as an example, it may help you understand the p

作业6--超级无敌终结(冲刺二)

核心类 1 package com.example.ddd; 2 3 public class Core { 4 int a; 5 int b; 6 int c; 7 int d; 8 public Core(int a,int b,int c,int d) 9 { 10 this.a=a; 11 this.b=b; 12 this.c=c; 13 this.d=d; 14 } 15 public int calc() 16 { 17 if(c==0) 18 { 19 return a+b; 2

leetcode LinkList专题

此次blog会将leetcode上的linklist专题内容放在这里,后续慢慢添加 一:leetcode 206 Reverse Linked List  二:leetcode 92 Reverse Linked List II 一:leetcode 206 Reverse Linked List 题目: Reverse a singly linked list. 代码: class Solution { public: ListNode* reverseList(ListNode* head)

[LeetCode] Reverse Linked List II 倒置链表之二

Reverse a linked list from position m to n. Do it in-place and in one-pass. For example:Given 1->2->3->4->5->NULL, m = 2 and n = 4, return 1->4->3->2->5->NULL. Note:Given m, n satisfy the following condition:1 ≤ m ≤ n ≤ lengt

Linked List专题二(cc charpter2)

Reverse Nodes in k-Group Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is. You may not alter the valu

[LeetCode] Linked List Cycle II 单链表中的环之二

Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Follow up: Can you solve it without using extra space? 这个求单链表中的环的起始点是之前那个判断单链表中是否有环的延伸,可参见我之前的一篇文章 (http://www.cnblogs.com/grandyang/p/4137187.html). 还是要设

浙大数据结构课后习题 练习二 7-2 Reversing Linked List (25 分)

Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K=3, then you must output 3→2→1→6→5→4; if K=4, you must output 4→3→2→1→5→6. Input Specification: