数据结构与算法——线性表链式存储结构(静态链表)

今天总结静态链表.

什么是静态链表?

我理解静态链表是一种伪链表,因为它没有使用指针。静态链表使用数组实现的,这个数组是一个结构体数组,结构体由数据域和指针域构成,与单链表不同的是,这个指针域并不是指针,而是一个整数,用来指向下一个结点(数组下标)。

静态链表中实际上相当于有两个链表,一个时实际数据所构成的一个链表,另一个是数组中空元素所构成的链表,称为空闲链表或备用链表,用来存放插入进来的元素。

心得:静态链表感觉比单链表,双向链表绕很多,看书的时候,书上在释放结点空间那块写的很复杂,后来和我实现的发现对不上。于是,根据静态链表的理解,原理,自己实现,可能实现方法和书上或网上的不太一样,但是我觉得思路与原理是一样的。有不对的地方,希望能给指出来,我也是才学习这一块。

实现代码:

<span style="font-family:Courier New;font-size:14px;">#include <iostream>

using namespace std;
const int MAX_SIZE = 100;
template <class T>
struct StaticNode {
    T data;
    int next;
};

template <class T>
class StaticLinkList {
public:
    StaticLinkList();
    StaticLinkList(T a[],int n);
    void Insert(int i,T x);        //在位置i处插入元素a
    T Delete(int i);               //删除第i个元素,返回被删的元素值
    int Get(int i);                //查找位置为i处的元素 返回在数组中的下标
    int NewNode();                 //申请结点空间
    void DeleteNode(int i);        //释放游标i指向的结点
    void PrintStaticLinkList();    //遍历链表
    int GetLength();               //获取链表的长度
private:
    int front;
    int tail;
    StaticNode<T> SArray[MAX_SIZE];
};

template <class T>
StaticLinkList<T>::StaticLinkList() {
    front = -1;         //空链表的头指针指向-1
    tail = 0;           //未分配空间的第一个元素的下标
    for(int i=0;i<MAX_SIZE-1;i++) {
        SArray[i].next = i+1;  //每个元素的next域指向下一个元素
    }
    SArray[MAX_SIZE-1] = -1; //最后一个元素的next域设为-1
}

template <class T>
StaticLinkList<T>::StaticLinkList(T a[],int n) {
    for(int i=0;i<MAX_SIZE-1;i++) {
        SArray[i].next = i+1;
    }
    SArray[MAX_SIZE-1].next = -1;
    for(int i=0;i<n;i++) {
        SArray[i].data = a[i];
    }
    front = 0;     //头指针指向第一个起始元素
    tail = SArray[n-1].next;  //指向第一个未分配空间的元素
    SArray[n-1].next = -1;   //将最后一个元素的next域设为-1

}

template <class T>
void StaticLinkList<T>::PrintStaticLinkList() {
    int k;
    if(front!=-1)   //front不为-1 链表非空 将当前头指针赋给k
         k = front;
    while(SArray[k].next!=-1) {
        cout<<SArray[k].data<<" ";
        k = SArray[k].next;
    }
    cout<<SArray[k].data;  //将next域等于-1的元素打印出来 即就是最后一个元素
    cout<<endl;
}

template <class T>
void StaticLinkList<T>::Insert(int i,T x) {
       int k = front;
       for(int j=1;j<i-1;j++) {
         k = SArray[k].next;
       }
       int p = NewNode();  //申请一个空间 实质是将第一个空闲空间的数组下标取出来
       SArray[p].data = x;
       SArray[p].next = SArray[k].next;
       SArray[k].next = p;
}

/**
    申请空间 该方法返回第一个为分配空间的元素的下标
*/
template <class T>
int StaticLinkList<T>::NewNode() {
    if(tail==-1) throw "空间不足";
    int pos = tail;
    tail = SArray[tail].next;
    return pos;
}

template <class T>
int StaticLinkList<T>::GetLength() {
    int count = 1; //计数器
    int p ;
    //链表非空
    if(front!=-1)
        p = front;
    while(SArray[p].next!=-1) {
        count++;
        p = SArray[p].next;
    }
    return count;

}
/**
    获取指定位置元素的所在数组中的下标
    思路:
    无论元素在数组中的什么位置,我们只要遍历获取到前一个位置元素
    那么它的next域指向的就是后继元素的数组下标
*/
template <class T>
int StaticLinkList<T>::Get(int i) {
    int p = front;
    for(int j=0;j<i-1;j++) {
        p = SArray[p].next;
    }
    return p;
}

/**
    释放结点所占的空间
    这里的释放其实 是将待删结点加入到空闲链表中 并没有动用数组本身
    所做的事情还是移动游标
*/
template <class T>
void StaticLinkList<T>::DeleteNode(int i) {
    if(i<0||i>MAX_SIZE-1||front==-1) throw "释放空间错误";
    SArray[i].next = tail;
    tail = i;

}
/**
    删除结点元素 这里要做的就是移动游标 使前一个结点指向待删结点的后一个结点
*/
template <class T>
T StaticLinkList<T>::Delete(int i) {
    int p = front;
    for(int j=1;j<i-1;j++) {
        p = SArray[p].next; //当前结点的前一个结点(数组下标)
    }

    int k = SArray[p].next; //当前待删结点的数组下标
    T x = SArray[k].data;
    SArray[p].next = SArray[k].next;
    DeleteNode(k);  //释放结点 参数为待删元素所在数组的下标
    return x;
}
int main()
{
    int a[6] = {1,5,6,8,3,0};
    StaticLinkList<int> SLinkList(a,6);
    cout<<"链表长度为:"<<endl;
    cout<<SLinkList.GetLength()<<endl;
    cout<<"遍历静态链表"<<endl;
    SLinkList.PrintStaticLinkList();
    cout<<"在位置3处插入元素4"<<endl;
    SLinkList.Insert(3,4);
    SLinkList.PrintStaticLinkList();
    cout<<"获取位置3的元素所在数组的下标:"<<endl;
    cout<<SLinkList.Get(3)<<endl;
    cout<<"删除位置4的元素"<<endl;
    SLinkList.Delete(4);
    SLinkList.PrintStaticLinkList();
    cout<<"在位置4处插入元素9"<<endl;
    SLinkList.Insert(4,9);
    SLinkList.PrintStaticLinkList();
    return 0;
}
</span>
时间: 2024-09-29 20:07:41

数据结构与算法——线性表链式存储结构(静态链表)的相关文章

数据结构与算法——线性表链式存储(单链表)

今天总结单链表的实现. 什么是链表? 就是采去链式存储结构的线性表,所谓链式存储就好比火车的车厢一样,一节一节的连接起来,成为一个线性表.这种方式采用动态存储分配方式,即程序在运行时根据实际需要申请内存空间,不需要时将内存空间释放掉. 链表用一组任意的存储单元存放线性表中的各个元素,这组存储单元可以是连续的,也可以是不连续的. 什么是单链表? 单链表简单理解就是单向的,就像火车一样.如果将火车头与火车为连接在一块,就构成了循环链表. 链表的结构:链表采用节点结构,这个节点分为两部分,一部分存储数

数据结构与算法——线性表链式存储(单循环链表)

今天总结循环单链表 什么是单循环链表? 单链表终端结点的指针域是指向空的,如果将其指向头结点,这样就形成了一个环,那么这种首尾相接的环就够成了单循环链表. 单链表中我们都是用头指针来表示的,但是在单循环链表里,用尾指针(指向最后一个节点).为什么要这样,因为如果用头指针,那么当查找最后一个元素的时候,就要循环遍历,时间复杂度为O(n),如果用尾指针,时间复杂度为O(1),而因为是循环的,所以头指针很容易表示出来即rear->next,时间复杂度也是O(1) 单循环链表中需要注意两点: 头指针使用

数据结构与算法——线性表链式存储(双向循环链表)

今天总结线性表中的双向循环链表. 什么是双向循环链表? 看名字估计也就知道了,首相他是一个循环链表,也就是最后一个结点的指针域不为空,而是指向头结点,其次与单向循环链表相比,它是双向的.所谓双向,就是给每个结点再增加一个指针域,这个指针域指向前一个结点. 即是下面这样(来自百度图片): 为什么要用双向循环链表? 无论单链表还是单向循环链表,都只有一个指针域,它们都是直接指向后继结点的,如果要查找当前结点的后继结点,会很方便.但是如果给定一个结点,要得到它的前继结点,就会很麻烦,必须从第一个元素开

线性表链式存储结构的c语言实现

线性表链式存储结构的c语言实现的操作 <1>定义链式存储结构的结点. <2>初始化线性表 <3>判定是否为空 <4>清空列表 <5>返回L中数据元素个数 <6>用e返回L中第i个数据元素的值 <7>返回L中第1个与e满足关系的数据元素的位序,若没有则返回0 <8>在L中第i个位置之前插入新的数据元素e,L的长度加1 <9>删除L的第i个数据元素,并用e返回其值,L的长度减1 <10>依次

05.线性表(四)链式存储结构.静态链表

链式存储结构.静态链表   一.静态链表 1.静态链表存储结构 单链表是通过指针实现的,但是我们也可以通过数组来代替指针描述单链表,即静态链表.如何实现静态链表?构造数组的元素由两个数据域组成:data和cur,即数组的每个下标都对应一个data和一个cur. 数据域data:用来存放数据元素,即要处理的数据: 游标cur:存放该元素的后继在数组中的下标,相当于单链表中的next指针: 为了方便插入数据,我们通常会把数组建立得大一些,以便有一些空闲空间而不致于出现溢出情况. 线性表的静态链表存储

数据结构 - 线性表链式存储结构

链式存储 链式存储 :用一组任意的存储单元存储线性表中的数据元素.用这种方法存储的线性表简称线性链表. 存储链表中结点的一组任意的存储单元可以是连续的,也可以是不连续的,甚至是零散分布在内存中的任意位置上的. 链表中结点的逻辑顺序和物理顺序不一定相同.(即不要求逻辑上相邻的元素在物理位置上也相邻) 为了正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其直接后继结点的地址(或位置),称为指针(pointer)或链(link),这两部分组成了数据元素ai的存储映像 链表是通过每个结点

【C语言--数据结构】线性表链式存储结构

直接贴代码 头文件 #ifndef __LINKLIST_H__ #define __LINKLIST_H__ typedef void LinkList; typedef struct _tag_LinkListNode { LinkList* next; }LinkListNode; LinkList* LinkList_create(); void LinkList_Destroy(LinkList* pstList); void LinkList_Clear(LinkList* pstL

线性表链式存储结构

链式存储 :用一组任意的存储单元存储线性表中的数据元素.用这种方法存储的线性表简称线性链表.存储链表中结点的一组任意的存储单元可以是连续的,也可以是不连续的,甚至是零散分布在内存中的任意位置上的. 为了正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其直接后继结点的地址(或位置),称为指针(pointer)或链(link),这两部分 组成了链表中的结点结构,如下图所示. data :数据域,存放结点的值.next :指针域,存放结点的直接后继的地址. 指针域和数据域组成数据元素称

03.线性表(二)链式存储结构.单链表1

链式存储结构.单链表1 1.基本概念 为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置) (1)数据域:存储线性表数据元素数据信息的域称为数据域: (2)指针域:把存储直接后继位置(下一个数据元素的地址)的域称为指针域,指针域中存储的信息为指针或链: (3)结点(Node):由数据域和指针域两部分信息组成数据元素ai的存储映像,称为结点. (4)头指针:把链表中第一个结点的存储