模板(双向链表与队列)

本文探讨了双向链表的结构特点,包括其数据域和两个指针域,以及相对于单链表的优势。文章指出,由于双向链表在插入和删除操作上的便利,适合用于实现“先进先出”的队列。通过模板编程,作者展示了如何用C++实现双向链表及队列的基本功能,提供了一段具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       ”双向链表与队列“


          “双向链表”是包含两个指针域,一个数据域,既有指向前驱的指针,还有指向后继的指针,同时可以从两个方向对链表进行遍历,访问各个节点。“双向链表”较”单链表“在插入和删除节点方面更为简单,但是所占的空间比“单链表”大。“队列”的实现之所以选择使用双向链表,是因为队列的特点是“先进先出”,如若使用顺序表则很大程度上的浪费空间。在这样的情境下,链表较顺序表更为合适。


            根据“模板”的概念,设计并实现双向链表,进而实现队列的基本功能。下面是利用模板来实现双向链表的具体代码:


#pragma once
#include <assert.h>

//双向链表 
template <class T>
struct ListNode
{
     T _data;
     ListNode<T> * _next;
     ListNode<T> * _prev;
     ListNode(const T& x)
        :_data(x)
        , _next(NULL)
        , _prev(NULL)
     { }
};

template <class T>
class List
{
public:
    List()    //构造函数
       :_head(NULL)
       , _tail(NULL)
    { }
    
    ~List()   //析构函数
    {
        Clear();
    }
    
public:
    void pushBack(const T & x)     //尾插
    {
        if (_head == NULL)
        {
             _head = _tail = new ListNode<T>(x);
         }
        else
        {
            ListNode<T> * tmp = new ListNode<T>(x);
            _tail->_next = tmp;
            tmp->_prev = _tail;
            _tail = tmp;
            tmp->_next = NULL;
        }
    }
    
    void popBack()    //尾删
    {
        if (_head == NULL)
        {
            return;
        }
        else if (_head == _tail)
        {
            delete _tail;
            _head = _tail = NULL;
         }
        else
        {
            ListNode<T> * tmp = _tail->_prev;
            delete _tail;
            tmp->_next = NULL;
            _tail = tmp;
        }
    }
    
    void pushFront(const T & x)     //头插
    {
        ListNode<T> * tmp = new ListNode<T>(x);
        if (_head == NULL)
       {
           _head = _tail = tmp;
       }
        else
        {
            tmp->_next = _head;
            tmp->_prev = NULL;
            _head = tmp;
        }
     }
     
     void popFront()     //头删
     {
         if (_head == _tail)
         {
             if (_head)
             {
                 delete _head;
                 _head = _tail = NULL;
             }
         }
         else
        {
            ListNode<T> * tmp = _head->_next;
            delete _head;
            _head = tmp;
            tmp->_prev = NULL;
        }
     }
     
      void Insert(ListNode<T> * pos,const T& x)    //在pos位置上插入数据x
     {
         assert(pos);
         ListNode<T> * tmp = new ListNode<T>(x);
         ListNode<T> * cur = pos->_next;
         tmp->_next = cur;
         cur->_prev = tmp;
         tmp->_prev = pos;
         pos->_next = tmp;
     }
     
      void Erase(ListNode<T> * pos)    //删除pos位置上的数据
     {
         assert(pos);
         if (_head == NULL)
         {
             return;
          }
         else if (_head == _tail)
         {
             delete _head;
          }
         else
         {
             ListNode<T> * cur = pos->_next;
             ListNode<T> * tmp = pos->_prev;
             tmp->_next = cur;
             cur->_prev = tmp;
             delete pos;
         }
      }
      
      ListNode<T> * Find(const T & x)     //查找
     {
          ListNode<T> * tmp = _head;
          while (tmp)
         {
             if (tmp->_data == x)
            {
                return tmp;
             }
             tmp = tmp->_next;
         }
         if (tmp->_next)
        {
            return NULL;
         }
     }
     
     T & Top()     //读取队头元素
     {
         return _head->_data;
      }
      
     T & Back()     //读取队尾元素
    {
        assert(size > 0);
        return _tail->_data;
     }

     void Reverse()     //逆置
     {
         swap(_head, _tail);
         ListNode<T>* tmp = _head;
         while (tmp)
        {
            swap(tmp->_prev, tmp->_next);
            tmp = tmp->_next;
        }
     }
     
     void Sort()      //冒泡排序
     {
         ListNode<T> * cur = _head;
         ListNode<T> * tmp = _head->_next;
         while (tmp)
         {
             if (cur->_data > tmp->_data)
             {
                 T ptr = cur->_data;
                 cur->_data = tmp->_data;
                 tmp->_data = ptr;
             }
             cur = cur->_next;
             tmp = tmp->_next;
         }
      }
      
     void Unique()    //在有序链表中,去掉重复的数据
    {
        ListNode<T> * cur = _head;
        ListNode<T> * tmp = _head->_next;
        while (tmp)
       {
           while (cur->_data == tmp->_data)
          {
              ListNode<T>* str = tmp;
              tmp = tmp->_next;
              Erase(str);
          }
          cur = cur->_next;
          tmp = tmp->_next;
       }
    }
    
     void Merge(List<T> & s)    //将某一个链表连接到这个链表后面
     {
         _tail->_next = s._head;
         s._head->_prev = _tail;
      }
      
     void Splice(ListNode<T> * pos, List<T> & s)    //将一个链表连接到pos位置后面
    {
        assert(pos);
        if (pos == _tail)
        {
            Merge(s);
        }
        else
       {
            ListNode<T> *  cur = pos;
            ListNode<T> * tmp = pos->_next;
            ListNode<T> * str = s._tail;
            cur->_next = s._head;
            s._head->_prev = cur;
            str->_next = tmp;
            tmp->_prev = str;
        }
    }
    
     size_t Size()    //计算链表中的元素个数
    {
         ListNode<T> * tmp = _head;
         int count = 0;
         while (tmp)
        {
            count++;
            tmp = tmp->_next;
        }
         return count;
     }
     
     void print()   //格式输出
     {
         ListNode<T> * tmp = _head;
         while (tmp)
         {
             cout << tmp->_data << " ";
             tmp = tmp->_next;
          }
         cout << endl;
      }

    void Clear()
    {
        ListNode<T> * tmp = _head;
        while (tmp)
       {
           ListNode<T> * str = tmp;
           tmp = tmp->_next;
           delete str;
       }
    }

private:
    ListNode<T> * _head;
    ListNode<T> * _tail;
};


       对于”队列“能够利用上述双向链表的功能来实现,下面就是基本的程序代码:


#pragma once
#include <string>

//队列
#include <assert.h>
#include "ListNode.h"
template <class T , template<class> class container = List>
class Queue
{
public:
     void push(const T & x)   //进入队列
    {
        _con.pushBack(x);
     }
     
     void pop()         //出队列
    {
        _con.popFront();
     }
     
     bool Empty()    //判断队列是否为空
    {
        return _con.Size() == 0;
     }
     
     size_t size()    //计算队列中的元素个数
    {
        return _con.size();
    }
    
     T & top()    //队头节点
     {
        return _con.Top();
     }
     
     T & Back()    //队尾节点
    {
        return _con.Back();
     }
     
     void print()    //格式输出
    {
        _con.print();
     }
     
private:
     container<T> _con;
};


本文出自 “无心的执着” 博客,谢绝转载!

/* * 基于双向链表实现双端队列结构 */ package dsa; public class Deque_DLNode implements Deque { protected DLNode header;//指向头节点(哨兵) protected DLNode trailer;//指向尾节点(哨兵) protected int size;//队列中元素的数目 //构造函数 public Deque_DLNode() { header = new DLNode(); trailer = new DLNode(); header.setNext(trailer); trailer.setPrev(header); size = 0; } //返回队列中元素数目 public int getSize() { return size; } //判断队列是否为空 public boolean isEmpty() { return (0 == size) ? true : false; } //取首元素(但不删除) public Object first() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); return header.getNext().getElem(); } //取末元素(但不删除) public Object last() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); return trailer.getPrev().getElem(); } //在队列前端插入新节点 public void insertFirst(Object obj) { DLNode second = header.getNext(); DLNode first = new DLNode(obj, header, second); second.setPrev(first); header.setNext(first); size++; } //在队列后端插入新节点 public void insertLast(Object obj) { DLNode second = trailer.getPrev(); DLNode first = new DLNode(obj, second, trailer); second.setNext(first); trailer.setPrev(first); size++; } //删除首节点 public Object removeFirst() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); DLNode first = header.getNext(); DLNode second = first.getNext(); Object obj = first.getElem(); header.setNext(second); second.setPrev(header); size--; return(obj); } //删除末节点 public Object removeLast() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); DLNode first = trailer.getPrev(); DLNode second = first.getPrev(); Object obj = first.getElem(); trailer.setPrev(second); second.setNext(trailer); size--; return(obj); } //遍历 public void Traversal() { DLNode p = header.getNext(); while (p != trailer) { System.out.print(p.getElem()+" "); p = p.getNex
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值