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

今天总结循环单链表

什么是单循环链表?

单链表终端结点的指针域是指向空的,如果将其指向头结点,这样就形成了一个环,那么这种首尾相接的环就够成了单循环链表.

单链表中我们都是用头指针来表示的,但是在单循环链表里,用尾指针(指向最后一个节点)。为什么要这样,因为如果用头指针,那么当查找最后一个元素的时候,就要循环遍历,时间复杂度为O(n),如果用尾指针,时间复杂度为O(1),而因为是循环的,所以头指针很容易表示出来即rear->next,时间复杂度也是O(1)

单循环链表中需要注意两点:

  • 头指针使用rear->next表示的
  • 判断某结点是否为尾结点条件是:rear->next==rear 而不是单链表中的p->next==NULL

图示(百度图片截取):

心得:在写链表这块的时候,由于指针有时会被绕,但我发现,一定要记住指针存放的就是地址,而这个地址通常表示的是一个结点。比如rear->next 代表的是头指针,而头指针里存放的地址是头结点的,也就是指向头结点,其实就代表了是头结点。指针这块需要好好的理解,揣摩,我是认为宁可慢一点,想明白了,也比快了,糊里糊涂的效果更好。

具体代码实现:

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

using namespace std;
template <class T>
struct Node{
    T data;
    struct Node<T> *next; //指针域
};
template <class T>
class CLinkList {
public:
    //初始化空的循环单链表
    CLinkList() {
        rear = new Node<T>;
        rear->next = rear;
    }
    CLinkList(T a[],int n);  //初始化一个链表
    ~CLinkList();     //析构函数
    int GetLength();  //获取单链表的长度
    T  Get(int i);  //获取线性表第i个位置上的元素
    int Locate(T x);  //查找线性表中值为x的元素 返回其位置
    void Insert(int i,T x); //将元素x插入到位置i上
    T Delete(int i); //删除位置i上的元素 并将删除元素返回
    void PrintLinkList(); //循环遍历循环单链表中的各个元素

private:
    Node<T> *rear;   //尾指针
};

/**
    尾插法 用数组元素初始化循环单链表
    思路:
    1.新建一头结点,尾指针指向此头结点
    2.将头结点地址赋值给头结点指针域 即构成了一个空的单循环链表
    3.for循环 开始插入节点。
     3.1新建一个结点,将数组元素赋值给结点的数据域
     3.2使新建结点的指针域指向头结点的指针域 形成循环
     3.3将当前结点指向新建结点
     3.4尾指针向后移一位
*/
template <class T>
CLinkList<T>::CLinkList(T a[],int n) {
    rear = new Node<T>;
    rear->next = rear;
   //采用尾插法
    for(int i=0;i<n;i++) {
        Node<T> *s= new Node<T>;
        s->data = a[i];
        s->next = rear->next ;
        rear->next = s;
        rear = rear->next; //尾指针向后移
    }
}
template <class T>
int CLinkList<T>::GetLength() {
    int count = 0; //计数器
    Node<T> *p = rear->next;
    while(p!=rear) {
        count++;
        p = p->next;
    }
    return count;
}

/**
    析构函数 用来释放结点
*/
template <class T>
CLinkList<T>::~CLinkList() {
    Node<T> *p = rear->next; //初始化工作指针
    Node<T> *q;  //临时结点
    while(p!=rear) {
        q = p;
        p = p->next;
        delete q;
    }
}

template <class T>
T CLinkList<T>::Get(int i) {
    if(i>GetLength()||i<1) return -1; //判断查找的位置是否是合理的
    Node<T> *p = rear->next;
    for(int j=0;j<i;j++) {
        p = p->next;     //得到位置i的节点
    }
    return p->data;
}

template <class T>
int CLinkList<T>::Locate(T x) {
    Node<T> *p = rear->next;
    int j=0;
    while(p!=rear) {
        if(p->data==x) return j;
        j++;
        p = p->next;
    }
    return -1;
}

template<class T>
void CLinkList<T>::Insert(int i,T x) {
    Node<T> *p = rear->next;
    //获取前一个结点
    for(int j=0;j<i-1;j++) {
        p = p->next;
    }
    Node<T> *s = new Node<T>;
    s->data = x;
    s->next = p->next;
    p->next = s;

}

template <class T>
void CLinkList<T>::PrintLinkList() {
    Node<T> *p = rear->next;  //这里是头结点
    for(int i=0;i<GetLength();i++) {
        cout<<p->next->data<<" "; //下一个节点的数据域
        p = p->next;
    }
    cout<<endl;
}

template<class T>
T CLinkList<T>::Delete(int i) {
    Node<T> *p = rear->next;
    for(int j=0;j<i-1;j++) {
        p = p->next;
    }
    Node<T> *q = p->next; //要删除的结点
    p->next = q->next;
    T x = q->data;
    delete q;
    return x;
}

int main()
{
    int a[6] = {2,4,6,1,7,9};
    CLinkList<int> list(a,6);
    cout<<"遍历单链表的元素"<<endl;
    list.PrintLinkList();
    cout<<"循环单链表的长度:"<<endl;
    cout<<list.GetLength()<<endl;
    cout<<"获取位置2的元素:"<<endl;
    cout<<list.Get(2)<<endl;
    cout<<"获取元素6所在的位置"<<endl;
    cout<<list.Locate(2)<<endl;
    cout<<"插入元素8到位置3"<<endl;
    list.Insert(3,8);
    list.PrintLinkList();
    cout<<"栓出位置4上的元素"<<endl;
    list.Delete(4);
    list.PrintLinkList();
    return 0;
}
</span>

结果:

时间: 2024-09-30 11:49:20

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

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

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

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

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

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

今天总结静态链表. 什么是静态链表? 我理解静态链表是一种伪链表,因为它没有使用指针.静态链表使用数组实现的,这个数组是一个结构体数组,结构体由数据域和指针域构成,与单链表不同的是,这个指针域并不是指针,而是一个整数,用来指向下一个结点(数组下标). 静态链表中实际上相当于有两个链表,一个时实际数据所构成的一个链表,另一个是数组中空元素所构成的链表,称为空闲链表或备用链表,用来存放插入进来的元素. 心得:静态链表感觉比单链表,双向链表绕很多,看书的时候,书上在释放结点空间那块写的很复杂,后来和我

线性表链式存储结构的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>依次

线性表链式存储的实现详解

本文原创,转载请注明:http://blog.csdn.net/j903829182/article/details/38173681 #include<stdio.h> #include<malloc.h> //线性表的链式存储和实现,带头点 #define true 1 #define false 0 typedef int DataType;//定义抽象数据类型 //节点的结构体 typedef struct Node{ DataType data;//节点的数据域 stru

线性表链式存储的基本操作

线性表的顺序存储结构的特点是逻辑关系上相邻的两个元素在物理位置上也相邻,因此可以随机存取表中任意元素.线性表链式存储结构特点是用一组任意的存储单元存储数据元素,为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储本身信息外,还要存储指示其直接后继的信息(即直接后继的存储位置).这两部分信息称为数据元素ai的存储映像,称为结点(node).它包括两个域,其中存储数据信息的称为数据域,存储直接后继存储位置的域称为指针域. 1.线性表的单链表存储结构 typ

线性表链式存储设计与实现 - API实现

基本概念 链式存储定义 为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息外,还需要存储指示其直接后继的信息. 表头结点 链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息 数据结点 链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息 尾结点 链表中的最后一个数据结点,其下一元素指针为空,表示无后继. 链表技术领域推演 链表链式存储_api实现分析 在C语言中可以用结构体来定义链表中的指针域 链表中的表头结点也可以用结构体实现

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

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

浅谈数据结构之线性表链式存储(二)

前面我们所讲的线性表的顺序存储结构,它是有优缺点,最大的缺点是插入与删除时需移动大量的元素,这显然需要耗费许多时间.这时,我们就引入线性表的链式存储结构,它的特点是:用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的.这就意味着,这些数据可以存在内存中未被占用的任意位置上,即当线性表进行插入与删除时就不需要移动大量的元素了,节约了时间. 链式结构中,除了需要存储数据元素的信息外,还要存储它的后继元素的存储地址.我们把存储数据元素信息的域称为数据域,把存储直接后继