静态链表(C++实现)

用数组描述的链表,即称为静态链表。

在C语言中,静态链表的表现形式即为结构体数组,结构体变量包括数据域data和游标cur。

这种存储结构,仍需要预先分配一个较大的空间,但在作为线性表的插入和删除操作时不需移动元素,仅需修改指针,故仍具有链式存储结构的主要优点。

下图表示了静态链表的一中存储结构:

图中用彩色途上的是两个头结点,不存放数据,分别用来记录第一个备用节点和第一个数据节点的下标。

下面给出静态链表的C++实现代码:

首先给出头文件:StaticList.h:

#include<iostream>
#include<assert.h>
using namespace std;

#define MAXSIZE 20        // 静态链表(数组)默认长度
#define ElemType int      // 值类型

class StaticList;

//节点类
typedef class StaticListNode   // 静态链表的节点类型(数组元素类型)
{
    friend class StaticList;
private:
    ElemType data;              // 值域
    int      cur;               // 游标 (指示当前节点的下一个元素下标)
}StaticListNode;

//  静态链表类</strong></span>
class StaticList
{
public:
    StaticList()
    {
        for(int i = 2; i<MAXSIZE-1; ++i)
            space[i].cur = i+1;
        space[i].cur = 0;        //整个链表结束
        space[0].cur = 2;
        space[1].cur = 0;        //数据节点头的游标为空,没有数据
    }

    ~StaticList()
    {}

// 尾部插入法
    void push_back(const ElemType &x)
    {
        int i = Malloc_SL();
        if(0 == i)              // 空间申请失败
        {
            cout<<"已满!"<<x<<"不能插入"<<endl;
            return ;
        }
        space[i].data = x;
        space[i].cur = 0;

        int k = 1;
        while(0!=k && 0!=space[k].cur)  // 找到最后一个节点
            k = space[k].cur;

        space[k].cur = i;             // 把刚申请的下标为i的节点链到最后一个节点后面
    }

// 头部插入法
    void push_front(const ElemType &x)
    {
        int i = Malloc_SL();
        if(0 == i)            // 同上,空间申请失败
        {
            cout<<"已满!"<<x<<"不能插入"<<endl;
            return ;
        }
        space[i].data = x;    // 把x放入刚申请的节点中

        space[i].cur = space[1].cur;   // 此时刚申请的节点i的游标指向第一个数据节点,称为第一个结点
        space[1].cur = i;              // 使头结点指向第一个数据节点
    }

// 尾部删除
    void pop_back()
    {
        int i = space[1].cur;
        int j = 0;
        for(; 0!=space[i].cur; j = i, i = space[i].cur)
        {}    // 找到最后一个节点以及倒数第二个节点

        space[j].cur = 0;     // 倒数第二个节点的游标赋空
        Free_SL(i);           // 最后一个节点被释放
    }

// 头部删除
    void pop_front()
    {
        int i = space[1].cur;    // i是第一个数据节点的下标
        space[1].cur = space[i].cur;  // 头结点指向第二个数据节点的下标
        Free_SL(i);              // i 节点被释放
    }

    void show_list()
    {
        for(int i = space[1].cur; i!=0; i = space[i].cur)
            cout<<space[i].data<<" ";
        cout<<"Over"<<endl;
    }

    /* 静态链表从小到大排序的前提下,插入x  */
    void insert_val(const ElemType &x)
    {
        int k = 1;
        while(0!=k && 0!=space[k].cur && space[space[k].cur].data<x)
            k = space[k].cur;        //在下标k之后插入

        if(0 == space[k].cur)    // 如果k指向最后一个节点,执行尾插
            push_back(x);
        else if(k == 1)          // 如果k指向第一个节点,执行头插
            push_front(x);
        else                     // 在中间任意位置插入x
        {
            int i = Malloc_SL();
            assert(0 != i);
            space[i].data = x;
            space[i].cur = space[k].cur;   // i节点的游标指向k节点后面的一个节点
            space[k].cur = i;              // k节点的游标指向新开辟的i节点
        }
    }

    /* 返回key的前一个节点下标*/
    int find(const ElemType &key)
    {
        int i = 1;
        while(0!=i && space[space[i].cur].data!=key)
            i = space[i].cur;
        if(0 == i)
        {
            cout<<"没找到 "<<key<<endl;
            return -1;
        }
        return i;
    }

    /* 删除给定的值key所在节点,若没找到则返回 */
    void delete_val(const ElemType &key)
    {
        int i = find(key);
        if(-1 == i)      // 说明静态链表中没有元素key
            return ;
        else if(1 == i)  // key 处于下标为2的节点(第一个数据节点)
            pop_front();
        else if(0 == space[i].cur)  // key处于最后一个节点
            pop_back();
        else             // key 处于中间任意位置
        {
            int k = space[i].cur;   // 记录要删除位置的下标
            space[i].cur = space[k].cur;  // 脱离出要删除节点
            Free_SL(k);  // 删除key所在节点
        }
    }

    /* sl1 和 sl2已存在,把它们糅合到另一个链表,使之按非递减排列 */
    void merge(StaticList &sl1, StaticList &sl2)
    {
        sl1.sort();
        sl2.sort();
        if(0==sl1.length() || 0==sl2.length())
            return ;
        int p = sl1.space[1].cur;
        int q = sl2.space[1].cur;

        while(0!=p && 0!=q)
        {
            // 哪个数据较小,就把该数据尾插到新链表中,并使游标指向下一个
            if(sl1.space[p].data < sl2.space[q].data)
            {
                push_back(sl1.space[p].data);
                p = sl1.space[p].cur;
            }
            else
            {
                push_back(sl2.space[q].data);
                q = sl2.space[q].cur;
            }
        }
        while(0!=p)
        {        // 因为sl1已经有序,如果sl1还没有全部插入新链表,就把剩下的全部插入
            push_back(sl1.space[p].data);
            p = sl1.space[p].cur;
        }
        while(0!=q)
        {        // 因为sl2已经有序,如果sl2还没有全部插入新链表,就把剩下的全部插入
            push_back(sl2.space[q].data);
            q = sl2.space[q].cur;
        }
    }

    /* 如果静态链表无序,使其按非递减顺序排列 */
    void sort()
    {
        int s = space[1].cur;
        int p = space[s].cur;
        if(0 == p)
            return ;
        space[s].cur = 0;

        int k = 1;
        int k1 = 0;
        while(0 != p)
        {
            s = p;
            p = space[p].cur;

            k = 1;     // 找到一个位置k, 在k后插入s所指节点的数据
            while(0!=k && space[space[k].cur].data < space[s].data)
            {
                k1 = k;                  //如果k==0,用k1记录最后一个数据节点
                k = space[k].cur;        //在下标k之后插入
            }
            if(0 == k)    //尾插
            {
                space[k1].cur = s;
                space[s].cur = 0;
            }
            else          //头插和中间插
            {
                space[s].cur = space[k].cur;
                space[k].cur = s;
            }
        }
    }

    /* 逆置静态链表 */
    void reserve()
    {
        int s = space[1].cur;
        int p = space[s].cur;
        if( 0==p )
            return ;
        space[s].cur = 0;
        while(0 != p)
        {
            s = p;
            p = space[p].cur;

            space[s].cur = space[1].cur;   // 把s所指节点 头插进原有链表
            space[1].cur = s;              // s成为第一个数据节点
        }
    }

    /* 清空静态链表 */
    void clear()
    {
        for(int i = 2; i<MAXSIZE-1; ++i)
            space[i].cur = i+1;
        space[i].cur = 0;

        space[0].cur = 2;     // 下标2成为第一个备用节点
        space[1].cur = 0;     // 第一个数据节点为空
    }

    /* 返回表长 */
    int length()
    {
        if(0 == space[1].cur)
            return 0;
        int i = 1;
        int count = -1;
        do
        {
            ++count;
            i = space[i].cur;
        }while(0 != i);

        return count;
    }

    /* 返回下标为k的节点的下一个节点下标 在静态链表中用处不大*/
    int next(const int k)
    {
        if(0==k || 1==k)
            return -1;
        return space[k].cur;
    }
    /* 返回下标为k的节点的上一个节点下标 */
    int prio(const int k)
    {
        if(0==k || 1==k)
            return -1;
        int p = 1;
        while(0!=p && space[p].cur!=k)
            p = space[p].cur;
        return p;
    }

protected:
    /* 用来申请一个空间,返回该节点的下标 */
    int Malloc_SL()
    {
        int i = space[0].cur;   // 0下标的游标指向第一个备用节点
        if(space[0].cur) space[0].cur = space[i].cur;  // 修改头结点保存的第一个备用节点下标
        return i;
    }
    /* 释放下标为k的节点 */
    void Free_SL(int k)
    {
        space[k].cur = space[0].cur;    // 该节点的游标指向第一个备用节点
        space[0].cur = k;               // 该节点称为第一个备用节点
    }

private:
    StaticListNode space[MAXSIZE];
};

下面是测试代码:Main.cpp

#include"StaticList.h"

void main()
{
    StaticList SL;

    StaticList SL1;    //测试merge()
    StaticList SL2;

    SL1.push_back(1);
    SL1.push_back(9);
    SL1.push_back(0);
    SL1.push_back(6);
    SL1.push_back(999);

    SL2.push_back(5);
    SL2.push_back(8);
    SL2.push_back(100);

    ElemType Item = 0;
    int select = 1;
    while(select)
    {
        cout<<"********************************************"<<endl;
        cout<<"*[1] push_back           [2]  push_front   *"<<endl;
        cout<<"*[3] show_list           [4]  pop_back     *"<<endl;
        cout<<"*[5] pop_front           [6]  insert_val   *"<<endl;
        cout<<"*[7] length              [8]  find         *"<<endl;
        cout<<"*[9] merge               [10] delete_val   *"<<endl;
        cout<<"*[11] sort               [12] reserve      *"<<endl;
        cout<<"*[13] next               [14] prio         *"<<endl;
        cout<<"*[15] clear              [16] destroy      *"<<endl;
        cout<<"*[0] quit_sys                              *"<<endl;
        cout<<"********************************************"<<endl;
        cout<<"请选择:》";
        cin>>select;
        switch(select)
        {
        case 1:
            cout<<"输入要尾插的数据:(-1结束)>";
            while(cin>>Item && -1 != Item)
                SL.push_back(Item);
            break;

        case 2:
            cout<<"输入要头插的数据:(-1结束)>";
            while(cin>>Item && -1 != Item)
                SL.push_front(Item);
            break;

        case 3:
            SL.show_list();
            break;
        case 4:
            SL.pop_back();
            break;

        case 5:
            SL.pop_front();
            break;

        case 6:
            cout<<"输入要插入的数据:>";
            cin>>Item;
            SL.insert_val(Item);
            break;

        case 7:
            cout<<"链表长度为:"<<SL.length()<<endl;
            break;

        case 8:
            cout<<"输入要查找的数据:>";
            cin>>Item;
            SL.find(Item);
            break;

        case 9:
            SL.merge(SL1, SL2);
            break;

        case 10:
            cout<<"输入要删除的数据:>";
            cin>>Item;
            SL.delete_val(Item);
            break;

        case 11:
            SL.sort();
            break;

        case 12:
            SL.reserve();
            break;

        case 13:
            SL.next(0);
            break;

        case 14:
            SL.prio(0);
            break;

        case 15:
            SL.clear();
            break;

        case 16:
            SL.~StaticList();
            break;

        default:
            break;
        }
    }
}

下面是测试截图:

时间: 2024-07-31 00:53:34

静态链表(C++实现)的相关文章

c语言:建立简单的静态链表,它由3个学生数据的结点组成,要求输出各结点的数据

建立简单的静态链表,它由3个学生数据的结点组成,要求输出各结点的数据. 解:将第1个结点的起始地址赋给头指针head,将第2个结点的起始地址赋给第1个结点的next成员,将第3个结点的起始地址赋给第2个结点的next成员.第3个结点的next成员赋予NULL,这就形成了链表.为了建立链表,使head指向a结点,a.next指向b结点,b.next指向c结点,c.next=NULL的作用是使c.next不指向任何有用的存储单元. 程序: #include<stdio.h> struct Stud

静态链表 初始化 定位 Malloc Free 插入 删除

#include <stdio.h> #include <stdlib.h> #define OK 1 #define TRUE 1 #define ERROR -1 #define FALSE -1 #define OVERFLOW -2 #define ElemType int #define Status int typedef int ElemType typedef int Status #define MAX_SIZE 1000;//表最大空间 /* //线性表的基本操

第二章:3.线性表---静态链表的表示和实现

前言: 由于一些高级程序设计语言中,并没有 "指针" 类型,因此上一节中用指针来描述的单链表不能被实现,这时候我们就会使用另一种形式链表:静态链表. 目录: 1.线性表的链式表示和实现 1.1线性链表 单链表(指针型线性链表) 静态链表 1.2循环链表 1.3双向链表 正文: 线性表的静态单链表存储结构: #define MAXSIZE 100; //链表的最大长度 typedef   struct{ ElemType  data; int  cur; }component, SLin

静态链表用C语言实现

静态链表便于在不设指针类型的高级语言使用链表结构,静态链表用数组描述,数组的一个分量表示一个结点,同时用游标(指示器cur)代替指针来表示结点在数组中的相对位置. 另外我们对数组第一个和最后一个元素作为特殊元素处理,不存数据.数组的第一个元素,即下标为0的元素的cur存放备用链表的第一个结点的下标,而数组 最后一个cur则存放第一个有效数值的下标,相当于单链表中有结点的作用. /* 2016年10月11日10:47:23 静态链表 */ #include<stdio.h> #define MA

静态链表实现_详细注释

1 //SLinkList.h 2 3 #ifndef _SLINK_LIST_ 4 #define _SLINK_LIST_ 5 6 template<typename T> 7 class SLinkList 8 { 9 public: 10 SLinkList(int maxz = 100); 11 ~SLinkList(); 12 void CreateList(int n); 13 void Insert(int i, T e); 14 T Delete(int i); 15 T G

数据结构之线性表-链式存储之静态链表(二)

本人文笔较差,语文从来不及格,基础不好,写此类文章仅供自己学习,理解队列及其他知识,高手大神请略过.参考书籍 <数据结构与算法分析-Java语言描述>.<大话数据结构> 1.1 静态链表简介 用数组描述的链表叫静态链表.官方是这么给的定义.另一种描述方法叫游标实现法.先不管这些无聊的定义.先按我个人理解描述,再来个Java版的实现比较符合我的风格.另有一些树上说早期存在其他的高级语言没有对象,引用或者指针这样的东西,但是需要对于快插快删等批量操作的这种链式存储,这时候静态链表就起了

静态链表----数据结构(C语言版) 算法2.17 心得

今天学习了数据结构中的静态链表,刚开始有些语句不能理解,研究了大半天终于想通了.记录于此留待以后查看,同时,对于同样对静态链表有些许不理解的人一点启发.文章中难免有理解上的问题,请指正.下面进入正文. 一.静态链表结构 静态链表可以在不设"指针"类型的高级程序设计语言中使用链表结构.静态链表如下所示:   首先,了解一下静态链表.静态链表中跟单链表类似,包含有很多结点,第i个结点中有包括数据space[i].data,和游标cur,游标space[i].cur的值为下一个结点的数组下标

使用C语言描述静态链表和动态链表

静态链表和动态链表是线性表链式存储结构的两种不同的表示方式. 静态链表的初始长度一般是固定的,在做插入和删除操作时不需要移动元素,仅需修改指针,故仍具有链式存储结构的主要优点. 动态链表是相对于静态链表而言的,一般地,在描述线性表的链式存储结构时如果没有特别说明即默认描述的是动态链表. 下面给出它们的简单实现,关于线性表更为详尽的C语言的实现,可以参考 http://www.cnblogs.com/choon/p/3876606.html 静态链表 #define _CRT_SECURE_NO_

数组元素循环右移及静态链表

1. 静态链表 https://github.com/BodhiXing/Data_Structure/tree/master/StaticListDemo 2. 数组元素循环右移 https://pta.patest.cn/pta/test/17/exam/4/question/262 思路:不做循环,只是换方式打印输出. 1 #include <stdio.h> 2 #include <math.h> 3 4 5 int main() { 6 int n,m,i; 7 scan

能判断是否还有剩余空间的静态链表

第一次系统的学习数据结构是在半年前,看小甲鱼的数据结构与算法视频,自学的话有许多不懂得地方,什么AVL树,红黑树,图的最短路径,最小生成树...但总归对数据结构与算法有一个大体的印象,到现在随着不断写代码,做OJ题,愈发认识到数据结构与算法的重要性,打算再看一遍,现在看着:大话数据结构(程杰著),数据结构(C语言版严蔚敏著),不推荐新手使用 数据结构与算法分析(Mark Allen Weiss 著)这本书真的很难懂. 回归正题,我看了许多书有关静态链表的描述和代码发现都没有判断是否还有剩余空间,