使用链表存储信息

链表

链表是一种数据结构,由连接在一起的小容器组成。这些容器称为节点。链表中第一个节点称为头节点,最后一个称为尾节点。

链表有三种基本形式,从最简单到最复杂依次为:

  • 单链表
  • 双链表

创建链表

参考:https://blog.csdn.net/qq_41620518/article/details/81143414
https://blog.csdn.net/u011579908/article/details/68943524
我们以单链表为例:
step1: 先创建节点(单链表的节点包括:数据域和指针域)

struct ListNode{
    int m_key;
    ListNode* next;
};

节点也可以是类:

class Node //节点类
{
public:
    Node() {}//三种不同的节点创建方式
    Node(int n) { num = n; next = NULL; }
    Node(int n, Node *p) { num = n; next = p; }

    void setNum(int n) { num = n; }
    void setNext(Node *p) { next = p; }

    int getNum() { return num; }//利用set&&get函数来进行操作
    Node *getNext() { return next; }

private:
    int num;//此处仅存储了一个整数,实际上数据可以是任何形式。
    Node *next;//此处存放下一个指针
};

然后是创建链表:

void createList(ListNode* pHead){
    ListNode* p = pHead;
    for (int i = 1; i < 10; ++i) {
        ListNode* pNewNode = new ListNode;
        pNewNode->m_key = i; // 将新节点的值赋值为i
        pNewNode->next = NULL;
        p->next = pNewNode; // 上一个节点指向这个新建立的节点
        p = pNewNode; // p节点指向这个新的节点
    }
}

下面以一段代码来说明创建链表的过程:

#include <iostream>
using namespace std;
/* 创建一个单链表 */
struct ListNode{
    int m_key;
    ListNode* next;
};
void createList(ListNode* pHead){
    ListNode* p = pHead;
    for (int i = 1; i < 10; ++i) {
        ListNode* pNewNode = new ListNode;
        pNewNode->m_key = i; // 将新节点的值赋值为i
        pNewNode->next = NULL;
        p->next = pNewNode; // 上一个节点指向这个新建立的节点
        p = pNewNode; // p节点指向这个新的节点
    }
}
int main(){
    ListNode* head = NULL;
    head = new ListNode;
    head->m_key = 0;
    head->next = NULL;
    createList(head);
 
    return 0;
}

从main()函数开始,先是定义了一个ListNode结构类head的指针,并初始化为NULL;其后为head分配内存,初始化类成员,接着就是进入到创建链表的函数中。

  • 1.将pHead的地址赋予一个类的新指针p,此时p的地址与pHead的地址一样,对p操作就是对pHead操作;
ListNode* p = pHead;
  • 2、进入for循环,此时i=1

  • 3、创建一个类的新指针pNewNode,作为中间过程为以后存放新节点提供过渡;

ListNode* pNewNode = new ListNode;
  • 4、赋值,令此时的pNewNode的m_key为1,next地址为null;
pNewNode->m_key = i; // 将新节点的值赋值为i
pNewNode->next = NULL;
  • 5、让指针p的next指向pNewNode,此时,由于第一步,因此pHead的next地址也指向pNewNode。这样就实现了pHead的next指向链表中的第一个节点;
p->next = pNewNode; // 上一个节点指向这个新建立的节点
  • 6、将pNewNode的地址赋予p,即将pNewNode的m_key以及next赋予p->m_key为1;p->next为null,此时由于pHead的内存是由new来分配的,其地址不由p改变而改变,因此此时p的地址与pHead的地址不一样,对p操作不咋在等同于对pHead操作,也正因为这样,pHead的next地址将永远指向i=1时的pNewNode,即链表中的第一个节点;
p = pNewNode; // p节点指向这个新的节点
  • 7、当i=2时,又用new新建一个pNewNode,此时需要注意,此时的pNewNode与i=1时新建的pNewNode的地址不一样,即为不同的类对象。因此我们可以将i=1时新建的pNewNode人为的称为pNewNode1,i=2时称为pNewNode2;
ListNode* pNewNode = new ListNode;
  • 8、对pNewNode2->m_key与next赋值;
pNewNode->m_key = i; // 将新节点的值赋值为i
pNewNode->next = NULL;
  • 9、将pNewNode的地址赋予p->next 。此时需要注意,由于第6步,p的地址为pNewNode1的地址,因此对p操作就相当于对pNewNode1操作,所以此时pNewNode1的next地址即为pNewNode2的地址,这样就实现了第一个节点的next指向第二个节点。
p->next = pNewNode; // 上一个节点指向这个新建立的节点
  • 10、将pNewNode2的地址赋予p;
p = pNewNode; // p节点指向这个新的节点
  • 11、以此类推。

下面参考这篇文章 https://www.cnblogs.com/byonecry/p/4458821.html

向链表中插入值(单向链表)

//p节点后插入值为i的节点
void insertNode(Node *p, int i){
    Node* node = new Node;
    node->value = i;
    node->next = p->next;
    p->next = node;
}

删除链表中的值(单向链表)

当需要删除一个节点p时,只需要将p的前一个节点的next赋为p->next,但是由于是单向的,只知道p,无法知道p前一个节点,所以需要转换思路。将p下一个的节点覆盖到p节点即可,这样就等效于将p删除了。

void deleteNode(Node *p){
    p->value = p->next->value;
    p->next = p->next->next;
}

反向遍历链表

法一:反向遍历链表就类似于事先遍历的节点后输出,即“先进后出”,那么可以将链表遍历存放于栈中,其后遍历栈依次弹出栈节点,达到反向遍历效果。
法二:递归

//1.stack
void printLinkedListReversinglyByStack(Node *head){
    stack<Node* > nodesStack;
    Node* pNode = head;
    //遍历链表
    while (pNode != NULL) {
        nodesStack.push(pNode);
        pNode = pNode->next;
    }
    while (!nodesStack.empty()) {
        pNode=nodesStack.top();
        printf("%d\t", pNode->value);
        nodesStack.pop();
    }
}
//2.递归
void printLinkedListReversinglyRecursively(Node *head){
    if (head!=NULL) {
        if (head->next!=NULL) {
            printLinkedListReversinglyRecursively(head->next);
        }
        printf("%d\t", head->value);
    }
}

找出中间节点

用slow和fast指针标记,slow每次走一步,fast每次走两步,当fast到尾节点时,slow就相当于总长度的一半,即在中间节点。

//找出中间节点
Node* findMidNode(Node* head){
    Node* slow = head;
    Node* fast = head;
    while (fast->next != 0&&fast->next->next!=0) {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}

找出倒数第K个节点

用slow和fast指针标记,fast指针事先走k步,然后slow和fast同时走,当fast到达末节点时,slow在fast的前k个节点,即为倒数第k个节点。

//找出倒数第k个节点
Node* findKNode(Node* head,int k){
    Node *temp1 = head;
    Node *temp2 = head;
    while (k-->0) {
        if(temp2 == NULL){
            return NULL;
        }
        temp2 =temp2->next;
    }
    while (temp2->next != NULL&&temp2->next->next!=NULL) {
        temp1 = temp1->next;
        temp2 = temp2->next;
    }
    return temp1;
}

翻转链表

参考这篇文章 http://www.cnblogs.com/wanglei5205/p/8572458.html

//翻转链表
Node * reverseLinkedList(Node* head,int k){
    Node *reversedHead = NULL;
    Node *pNode = head;
    Node *pre = NULL;
    while (pNode!=NULL) {
        if (pNode->next==NULL) {
            reversedHead = pNode;
        }
        Node* nxt = pNode->next;
        pNode->next = pre;
        pre=pNode;
        pNode=nxt;
    }
    return reversedHead;
}
  • 0
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值