数组仿真链表以及效率的对比说明

今天读了几篇张新华编写的《算法竞赛宝典》一书第三部,有了一些心得。
了解链表的创建后,我们可以使用数组来模拟链表的相关操作(尽可能开辟一个较大内存,因为数组仿真不具备链表动态开辟内存的特点)。对于每个“链结”,用linkNum[i]来存放数组元素的值,linkPos[i]来存放下一个元素的地址(其实也就是下一个元素的位置)。
代码:

//数组仿真链表
#include<stdio.h>
#include<stdlib.h>
#define MAXN 100010
int linkNum[MAXN];  //分别存储元素的大小和链表中元素的指针 
int linkPos[MAXN];
int markPos;
int head=-1;
void linkInit()
{
    int i;
    markPos=0;
    head=0;
    for(i=0;i<MAXN;i++)
    {
        linkNum[i]=-1;
        linkPos[i]=-1;
    }
}
void createlink()   //初始创建 
{
    int i=0,j,num;
    while(~scanf("%d",&linkNum[i])&&linkNum[i])
    {
        linkPos[i]=i+1; //每个指针保存下一个点的坐标,模拟链表 
        i++;
    }
    markPos=i;
}
void output()
{
    int i;
    for(i=head;i<markPos;i=linkPos[i])
    {
        printf("%d ",linkNum[i]);
    }
    printf("\n");
}
void deletelink(int delete_num) //删除值为delete_num的元素 
{
    int i=head,pre=-1;
    while(i!=-1)
    {
        if(linkNum[i]==delete_num)
        {
            if(i==head)     //如果删除头指针,就更新位置 
                head=linkPos[head];
            else
                linkPos[pre]=linkPos[i];
            linkNum[i]=-1;
            linkPos[i]=-1;
            return ;
        }
        pre=i;
        i=linkPos[i];   //更新位置 
    }
}
void insert(int add_num)    //默认在链表前段加入元素 
{
    int i=1;
    while(linkNum[i]!=-1&&i<MAXN)   //找到空位 
        i++;
    linkNum[i]=add_num;
    linkPos[i]=head;
    head=i;
}
int main()
{
    int delete_num,add_num;
    linkInit();
    createlink();
    output();
    printf("delete:");
    scanf("%d",&delete_num);
    deletelink(delete_num);
    output();
    printf("add:");
    scanf("%d",&add_num);
    insert(add_num);
    output();
    return 0;
}

数组仿真代码的优化:
对于每删除一个指定元素,数组链表都要去依次查找,因此需要进行O(n)的操作。
一个很好的方法可以将时间复杂度减小到O(1):是使用的方式存储上一次删除的元素的坐标。
每次对链表进行删除操作时,只需要弹出栈顶元素的坐标即可,因为这个下标所对应的元素显然是空的。

指针与数组链表的比较:
一个常见的问题就是,遍历同样大小的数组和链表哪个快。如果觉得数组遍历与链表遍历同样快,都是O(1)的操作,那就错了。这里有个概念,因为觉得不错,我就直接从书上简单抄到这里。
memory hierarchy(存储层次结构):
计算机机中存在多种不同的存储器,各存储器的平均存取速度差别很大,如下表所示:
这里写图片描述
各级别存储器的速度差异非常大,CPU寄存器可以是内存速度的100倍!这就是为什么CPU生产厂家发明CPU缓存的原因,而这个CPU缓存,就是数组链表和指针链表区别的关键所在。
CPU缓存会把一片连续的内存读入,因为数组结构是连续的内存地址,所以数组的全部元素或者部分元素被连续存放在CPU缓存里边。而链表的结点是分散在堆空间的,因此CPU缓存无法帮忙,只能去读取内存。这样就解释了为什么数组链表的速度相比指针链表要快。

猜你喜欢

转载自blog.csdn.net/cprimesplus/article/details/82669932