数据结构与算法-----链表篇

链表

1.基本特征:由一系列内存中不连续的节点组成,每个节点除了保存数据以外,还需要保存其前后节点的地址——双向链表。

2.基本操作

1)追加

2)插入

3)删除

4)遍历

5)伪随机访问

示例:使用C++实现双向链表类,并演示结果;

#include <iostream>
using namespace std;
class List {
public:
    // 构造函数中初始化为空链表
    List (void) : m_head (NULL), m_tail (NULL) {}
    // 析构函数中销毁剩余的节点
    ~List (void) {
        for (Node* next; m_head; m_head = next) {
            next = m_head -> m_next;
            delete m_head;
        }
    }
    // 追加
    void append (int data) {
        /*
        Node* node = new Node;
        node -> m_data = data;
        node -> m_prev = m_tail;
        node -> m_next = NULL;
        m_tail = node;
        */
        m_tail = new Node (data, m_tail);
        if (m_tail -> m_prev)
            m_tail -> m_prev -> m_next = m_tail;
        else
            m_head = m_tail;
    }
    // 插入
    void insert (size_t index, int data) {
        for (Node* find = m_head; find;
            find = find -> m_next)
            if (index-- == 0) {
                Node* node = new Node (data,
                    find -> m_prev, find);
                if (node -> m_prev)
                    node -> m_prev -> m_next = node;
                else
                    m_head = node;
                node -> m_next -> m_prev = node;
                return;
            }
        throw OverBound ();
    }
    // 删除
    void erase (size_t index) {
        for (Node* find = m_head; find;
            find = find -> m_next)
            if (index-- == 0) {
                if (find -> m_prev)
                    find -> m_prev -> m_next =
                        find -> m_next;
                else
                    m_head = find -> m_next;
                if (find -> m_next)
                    find -> m_next -> m_prev =
                        find -> m_prev;
                else
                    m_tail = find -> m_prev;
                delete find;
                return;
            }
        throw OverBound ();
    }
    // 正遍历
    void forward (void) const {
        for (Node* node = m_head; node;
            node = node -> m_next)
            cout << node -> m_data << ‘ ‘;
        cout << endl;
    }
    // 反遍历
    void backward (void) const {
        for (Node* node = m_tail; node;
            node = node -> m_prev)
            cout << node -> m_data << ‘ ‘;
        cout << endl;
    }
    // 下标运算符
    int& operator[] (size_t index) {
        for (Node* find = m_head; find;
            find = find -> m_next)
            if (index-- == 0)
                return find -> m_data;
        throw OverBound ();
    }
    const int& operator[] (size_t index) const {
        return const_cast<List&> (*this) [index];
    }
    // 测长
    size_t length (void) const {
        size_t len = 0;
        for (Node* node = m_head; node;
            node = node -> m_next)
            len++;
        return len;
    }
private:
    // 越界异常
    class OverBound : public exception {
    public:
        const char* what (void) const throw () {
            return "链表越界!";
        }
    };
    // 节点
    class Node {
    public:
        Node (int data = 0, Node* prev = NULL,
            Node* next = NULL) :
            m_data (data), m_prev (prev),
            m_next (next) {}
        int   m_data; // 数据
        Node* m_prev; // 前指针
        Node* m_next; // 后指针
    };
    Node* m_head; // 头指针
    Node* m_tail; // 尾指针
};
int main (void) {
    try {
        List list;
        list.append (10);
        list.append (20);
        list.append (50);
        list.append (60);
        list.append (80);
        list.forward ();
        list.insert (1, 15);
        list.insert (3, 40);
        list.insert (6, 70);
        list.backward ();
        list.erase (1);
        list.erase (2);
        list.erase (4);
        list.forward ();
        size_t len = list.length ();
        for (size_t i = 0; i < len; i++)
            list[i]++;
        const List& cr = list;
        for (size_t i = 0; i < len; i++)
            cout << cr[i] << ‘ ‘;
        cout << endl;
//      cout << cr[10] << endl;
    }
    catch (exception& ex) {
        cout << ex.what () << endl;
        return -1;
    }
    return 0;
}

输出结果:

时间: 2024-11-07 18:53:51

数据结构与算法-----链表篇的相关文章

数据结构与算法-链表的基本操作---ShinPans

//链表操作:建立.插入.删除.查找.倒置.删除等基本操作 #include<stdio.h> #include<stdlib.h> typedef  struct LNode {       int data;       structLNode *next; }LNode,*Llist; LNode *creat_head();//创建一个空表 void creat_list(LNode *,int);//创建一个长度为n的线性链表 void insert_list(LNode

数据结构与算法-----队列篇

队列 1.基本特征:先进先出 2.基本操作:从后端(rear)压入(push),从前端(front)弹出(pop) 3.实现要点:初始化空间.从后端指针压入,从前端指针弹出, 循环使用,判空判满 实践1 :使用C++语言实现队列类并进行数据示例演示 #include <iostream> using namespace std; class Queue { public: // 构造函数中分配内存空间 Queue (size_t size) : m_data (new int[size]),

python数据结构与算法——链表

具体的数据结构可以参考下面的这两篇博客: python 数据结构之单链表的实现: http://www.cnblogs.com/yupeng/p/3413763.html python 数据结构之双向链表的实现: http://www.cnblogs.com/yupeng/p/3413800.html 我这里只实现了单链表的类型,代码也相对精简一点: 先构造关于节点的类: 1 class Node: 2 def __init__(self,data=None,next=None): 3 self

数据结构与算法-----总结篇

一.数据结构 程序设计=数据结构+算法 1.逻辑结构 1)集合:元素之间没有联系. 2)线性结构:元素之间存在前后顺序. 3)树形结构:元素之间存在一对多的父子关系. 4)图状结构:元素之间存在多对多的映射关系. 2.物理结构 1)顺序结构:用连续的空间存放数据元素. 优点:便于随机访问. 缺点:空间利用率低,插入删除不方便. 2)链式结构:用不连续的空间存放数据元素,每个数据元素中处理存放数据意外,还要存放下一个元素的地址. 优点:空间利用率高,插入删除方便. 缺点:随机访问不方便. 3.逻辑

数据结构和算法--链表一之单向链表的简单实现

链表在我们java中也是一种基础的数据结构,可以理解成是一种和数组同级的数组结构,正如我们所知,在我们使用这集合ArrayList和LinkedList的时候,总会学习底层数组实现的ArrayList和双向链表实现的LinkedList的区别.在这里,我们将要讲说的是单向链表的简单实现,让我们体会一下链表在实现增删改查的时候是怎么样的一个操作,在和前边涉及到的数组的增删改查进行对比,得到我们学习的结论,数组的增删效率低于链表结构,查改效率高于链表结构! 什么叫做单向链表,我们可以理解为一个一个节

数据结构与算法 - 链表

链表 题型1:数组和链表的区别是什么? 数组和链表的区别主要表现在以下几个方面: 1)逻辑结构.数组必须事先定义固定的长度,不能适应数据动态地增减.当数组中插入.删除数据项时,需要移动其他数据项.而链表采用动态分配内存的形式实现,可以适应数据动态第增减的情况,需要时可以用new/malloc分配内存空间,不需要时使用delete/free将已分配的空间释放,插入和删除元素不需要移动数据项. 2)内存结构.数组从栈中分配空间,链表从堆中分配空间. 3)数组中的数据在内存中是顺序存储的,而链表是随机

数据结构与算法 —— 链表linked list(02)

我们继续来看链表的第二道题,来自于leetcode: 两数相加 给定两个非空链表来代表两个非负整数,位数按照逆序方式存储,它们的每个节点只存储单个数字.将这两数相加会返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头. 示例: 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807 分析: 因为是位数按照逆序方式存储,所以链表的前置节点是地位,直接循环链表相加,生成新的

数据结构和算法-链表

链表分类 单向链表 双向链表 优势: 删除某个节点更加高效, 可以快速找到前驱节点 可以方便的在某个节点前插入元素 循环链表 当要处理的数据具有环形结构的时候, 适合循环链表. 如约瑟夫环问题 双向循环链表 数组的缺点是大小固定, 一旦声明长度就要占用连续的内存空间, 当空间不够用时更换更大的空间, 此时就需要将原数组的所有数据迁移过去, 比较费时. 链表则可以动态扩容. 数组在查询上可以更快, 链表在插入和删除上更快, 为了结合数组和链表的优点, 有同时使用的情况, 比如一个网站的用户注册,

数据结构与算法-链表查找倒数第K个值

查找链表中倒数第k个结点题目:输入一个单向链表,输出该链表中倒数第k个结点.链表的倒数第0个结点为链表的尾指针.链表结点定义如下: struct ListNode { int m_nKey; ListNode* m_pNext; }; int FindCoundDownInList(pListNode head,int num) { pListNode p1,p2; p1=p2=head; while(num-->0 && p1!=NULL) p1=p1->m_pNext; i