数组实现单链表

单链表常见的实现方法有两种,一种方式是定义一个结构体表示链表节点。比如:

struct node{
      int val;
      node* next;
};

然后就是通过next指针将链表的所有节点连接起来。如果涉及到链表节点的插入和删除操作,则只需要修改链表节点的指针即可。

这种方式有个明显的缺点,就是不能随机存取。如果要在某个节点之后插入或者删除节点,复杂度是O(n),因为要从头开始逐个遍历到需要插入或者删除的节点(通过next指针找)。所以用结构体实现的单链表缺点就是太慢了。当然还有一个原因就是C++里要new一个node比较慢。总之就是慢~

因此算法题中使用单链表往往是通过数组实现,数组实现的单链表可以通过下标来索引节点,可以直接通过下标找到某个节点的值和下一个节点的,因此数组实现的单链表的最大优点就是快(插入和删除操作都是O(1)的时间复杂度),毕竟数组的特点就是随机存取嘛。

这里结合一道题目来看数组实现单链表。
原题链接
数组实现单链表
数组实现单链表

这道题题意非常直白。就是需要实现一个单链表,这个链表支持三个操作:(1)在链表的表头插入一个节点;(2)删除某个数后面的数;(3)在某个数后面加入一个数(即插入节点)。
输入有若干行,每行都有可能是三个操作的其中之一,最后的输出就是经过所有操作之后从头到尾将链表输出。

来模拟一下样例吧。
数组实现单链表

来看一下实现。
要实现三个操作,我们可以额外定义三个函数分别表示上面三个操作。
这里分别命名为insertBeforeHead(int x)Insert(int k, int x)Delete(int k)。这里的x就是要插入的值,k就是要插入/删除节点的前一个位置(也就是在第k个节点之后进行插入/删除)。

这里要注意,第k个节点并不是当前链表从前往后数,而是从最开始计算,插入的第k个节点(也就是说前面插入的节点被删除了,并不会重新计算k)。

要用数组表示单链表,和结构体实现链表一样,每个节点都要有值和记录下一个节点的“指针”,因此我们可以开两个数组val和nex分别表示节点的数值和下一个节点的位置。
由于需要对链表头做操作(在链表头插入节点)和记录已经插入的节点的个数(因为要在第k个节点之后进行插入/删除操作),因此我们需要用两个“指针”记录头节点和当前操作的节点是第几个节点。
简单的说,head指向的就是链表头节点(第一个节点,不是附加头节点)的下标,idx表示当前用到的是第几个节点。

const int N = 1e5 + 5;
int val[N], nex[N], head, idx;    //head表示头节点的下标,idx表示已经插入的节点的个数

链表需要有初始化操作,不然headidx的值可能是不确定的。

void init() {
      head = -1;      //注意:这里的head并不是虚拟头节点,指向的就是链表的第一个节点,这样做主要是为了方便在头节点插入数据,最开始没有插入节点,head指向-1
      idx = 0;        //还没插入节点,idx为0
}

然后看一下在链表头节点(之前)插入节点。
由于head记录了原来的头节点,我们希望新插入一个节点,这个节点的值为x,且这个节点的**next指针**指向原来的head
看一下代码:

void insertBeforeHead(int x) {
      val[idx] = x;      //新插入一个值为x的节点
      nex[idx] = head;   //x的下一个节点是原来的头节点,表示在头节点之前插入x
      head = idx;        //head指针指向新节点
      ++idx;             //更新插入节点的个数
}

看一下如何在第k个节点之后插入一个节点。
首先肯定要创建一个值为x的节点:val[idx] = x;
且这个新节点的next指针指向第k+1个节点:nex[idx] = nex[k]. (nex[k]是原来的第k+1个节点,让新插入的节点指向这个节点)。
然后k的next指针也要更新,指向x: nex[k] = idx;
再更新一下已经插入的节点的个数:++idx;
这样就得到在第k个节点之后插入节点x的代码:

void Insert(int k, int x) {
      val[idx] = x;
      nex[idx] = nex[k];
      nex[k] = idx;
      ++idx;
}

然后就剩下在第k个节点之后删除节点的函数啦:
这个很简单,要让第k个节点之后的值不存在,就直接让第k个节点的next指针指向第k+2个节点,也就是跳过了第k+1个节点,这样第k+1个节点就社会性死亡了。

void Delete(int k) {
      nex[k] = nex[nex[k]];
}

这道题的完整代码如下:

#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
int val[N], nex[N], head, idx;

void init() {
    head = -1;
    idx = 0;
}

void insertBeforeHead(int x) {
    val[idx] = x;
    nex[idx] = head;
    head = idx;
    ++idx;
}

//在下标为k的节点后插入x
void Insert(int k, int x) {
    val[idx] = x;
    nex[idx] = nex[k];
    nex[k] = idx;
    ++idx;
}

//删除下标为k的节点的下一个节点
void Delete(int k) {
    nex[k] = nex[nex[k]];
}

int main() {
    int M;
    cin >> M;            //操作的个数
    init();              //操作之前需要对head和idx指针进行初始化
    while(M--) {
        char op;         //当前进行的操作
        int k, x;
        cin >> op;
        if(op == 'H') {     //在头节点之前插入一个节点
            cin >> x;
            insertBeforeHead(x);
        } else if(op == 'I') {    //在第k个节点之后插入一个节点
            cin >> k >> x;
            Insert(k - 1, x);            //由于idx初始为0,所以第k个节点的下标为k - 1
        } else if(op == 'D') {
            cin >> k;
            if(k == 0) {                  
                head = nex[head];
            } else {
                Delete(k - 1);            //由于idx初始为0,所以第k个节点的下标为k - 1
            }
        }
    }
    for(int i = head; i != -1; i = nex[i]) {
        cout << val[i] << ' ';
    }
    cout << endl;
    return 0;
}

原文链接: https://www.cnblogs.com/linrj/p/13307798.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    数组实现单链表

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/366684

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午4:54
下一篇 2023年3月2日 下午4:55

相关推荐