可以,比如,通过重载下标操作符

template <typename T> // assert: 0 <= r < size
T List<T>::operator[](Rank r) const { // O(r),效率低下,可偶尔为之,却不宜常用
    Posi(T) p = first(); // 从首节点出发
    while (0 < r--) p = p -> succ; // 顺数第 r 个节点
    return p -> data; // 目标节点
} // 任一节点的秩,亦即其前驱的总数

在节点 p(可能是 trailer)的 n 个(真)前驱中,找到等于 e 的最后者

template <typename T> // 从外部调用时,0 <= n <= rank(p) < _size
Posi(T) List<T>::find(T const &e, int n, Posi(T) p) const { // 顺序查找,O(n)
    while (0 < n--) // 从右向左,逐个将 p 的前驱与 e 比对
        if (e == (p = p -> pred) -> data) return p; // 直至命中或范围越界
    return NULL; .. 若越出左边界,意味着查找失败
} // header 的存在使得处理更为简洁
template <typename T>
Posi(T) List<T>::insertBefore(Posi(T) p, T const &e) {
    _size++;
    return p -> insertAsPred(e); // e 当作 p 的前驱插入
template <typename T> // 前插入算法(后插入算法完全对称)
Posi(T) ListNode<T>::insertAsPred(T const &e) { // O(10
    Posi(T) x = new ListNode(e, pred, this); // 创建(耗时 100 倍)
    pred -> succ = x; pred = x; return x; // 建立链接,返回新节点的位置
template <typename T> // 基本接口
void List<T>::copyNodes(Posi(T) p, int n) { // O(n)
    init(); // 创建头、尾哨兵节点并做初始化
    while (n--) { // 将起自 p 的 n 项依次作为末节点插入
        insertAsLast(p -> data); p = p -> succ;
template <typename T>
T List<T>::remove(Posi(T) p) { // O(1)
    T e = p -> data; // 备份待删除节点数值(设类型 T 可直接赋值)
    p -> pred -> succ = p -> succ;
    p -> succ -> pred = p -> pred;
    delete p; _size--; return e; // 返回备份数值
template <typename T>
List<T>::~List() { // 列表析构
    clear(); delete header; delete trailer; // 清空列表,释放头、尾哨兵
template <typename T> 
int List<T>::clear() { // 清空列表
    int oldSize = _size;
    while (0 < _size) // 反复删除首节点,直至列表变空
        remove(header -> succ);
    return oldSize;
} // O(n),线性正比于列表规模
template <typename T>
int List<T>::deduplicate() { // 剔除无序列表中的重复节点
    if (_size < 2) return 0; // 平凡列表自然无重复
    int oldSize = _size; // 记录原规模
    Posi(T) p = first(); Rank r = 1; // p 从首节点起
    while (trailer != (p = p -> succ)) { // 依次直到末节点
        Posi(T) q = find(p -> data, r, p); // 在 p 的 r 个(真)前驱中,查找与之雷同者
        q ? remove(q) : r++; // 若存在,则删除;否则秩递增
    } // assert:循环过程中的任意时刻,p 的所有前驱互不相同
    return oldSize - _size; // 列表规模变化量,即被删除元素总数
} // 正确性及效率分析的方法与结论,与 Vector::deduplicate() 相同

下一篇:《C++ 数据结构(三)列表(3)有序列表》

2.1.Queue ........... 队列接口 2.2.Stack .............. 栈接口 2.3.Set .................. 集合接口 2.4.Map ............... 映射接口 2.5.Merger .......... 自定义函数接口 2.6.UnionFind ..... 并查集接口 3.高级数据结构 3.1.ArrayQueue .......................... 队列_基于动态数组实现 3.2.LinkedListQueue .................. 队列__基于链表实现 3.3.LoopQueue ........................... 循环队列_基于动态数组实现 3.4.PriorityQueue ....................... 优先队列_基于最大二叉堆实现 3.5.ArrayPriorityQueue ............. 优先队列_基于动态数组实现 3.6.LinkedListPriorityQueue ..... 优先队列_基于链表实现 3.7.ArrayStack ............................. 栈_基于动态数组实现 3.8.LinkedListStack ..................... 栈_基于链表实现 3.9.BSTSet ..................................... 集合_基于二分搜索树实现 3.10.LinkedListSet ....................... 集合_基于链表实现 3.11.BSTMap ................................ 映射_基于二分搜索树实现 3.12.AVLTreeMap ....................... 映射_ 基于AVL树实现 3.13.LinkedListMap .................... 映射_基于链表实现 3.14.MaxHeap ............................. 最大二叉堆 3.15.SegmentTree ...................... 线段树 3.16.Trie ......................................... 字典树 3.17.QuickFind ............................ 并查集_基于数组实现 3.18.QuickUnion ......................... 并查集_基于树思想实现
删除无序数组中所有重复的元素一、前言二、解题思路思路1思路2、代码实现1.判断元素是否在数组中2.主函数3.完整代码四、总结 最近在复习王道老师的《数据结构考研复习指导》这本书,第2章线性表的课后题,有一题比较有意思: 从有序顺序表中删除删除所有其值重复的元素,使表中所有元素的值均不同 从有序的顺序表中去除重复元素还是很简单的,但是,如果从无序的顺序表中去重要怎么实现呢?下面分享一下我的解题思路 二、解题思路 其实可以先给无序的顺序表做个排序,变成有序的顺序表,也就是“降维打击”,按
虽然不常用,但也做了一篇总结给大家做参考。 无序列表 UL (unorder list的缩写) 定义:无序列表是一个项目的列表,此列项目默认使用粗体圆点(典型的小黑圆圈)进行标记。 无序列表始于 ul 标签。每个列表项始于 li 默认类型:ul type=”disc” 因为是默认类型,所以不需要写出来,直接ul即可。 显示形式为... 表格是用来显示数据的,那么列表就是用来布局的。 列表最大的特点就是整齐、整洁、有序,它作为布局会更加自由和方便。 根据使用场景不同,列表可以分为大类:无序列表、有序列表和自定义列表无序列表: 有序列表: 自定义列表: 2.1无序列表(重点) <ul>标签表示HTML页面中项目的无序列表,一般会以项目符号呈现列表项,而列表项使用<li>标签定义。 无序列表的基本语法格式如下: <li>列表项1</li>
在 C 语言中,可以使用链表来创建列表,并从尾部添加数据。 链表是一种动态数据结构,允许您在运行时动态地添加或删除元素。它由节点组成,每个节点都包含数据和指向下一个节点的指针。 要创建链表,需要定义一个结构体来表示每个节点,包括数据域和指针域。例如: struct node { int data; struct node *next; 然后,可以使用 malloc 函数为新节点分配内存,并使用指针操作来更新指针。例如,以下代码演示了如何在链表的尾部添加一个新节点: struct node *head = NULL; // 初始化头指针 // 创建新节点 struct node *new_node = (struct node*)malloc(sizeof(struct node)); new_node->data = 5; new_node->next = NULL; // 如果链表为空,则将新节点设为头节点 if (head == NULL) { head = new_node; } else { // 否则,遍历链表,找到最后一个节点 struct node *current = head; while (current->next != NULL) { current = current->next; // 将新节点添加到最后一个节点的后面 current->next = new_node; 注意:在使用链表时,需要注意内存管理