单链表

本文介绍了一个通用的单链表类实现,包括基本操作如插入、删除、遍历等,并提供了异常处理机制。此外,还实现了两种创建链表的方法:头插法和尾插法。

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

LISH.h

#ifndef _LISH_H_
#define _LISH_H_

template<class T>
class List 
{
    public:
        virtual void clear()=0;
        virtual bool empty()const=0;
        virtual int size()const=0;
        virtual void insert(int i,const T &value)=0;
        virtual void remove(int i)=0;
        virtual int search(const T&value)const=0;
        virtual T visit(int i)const=0;
        virtual void traverse()const=0;
        virtual void inverse()=0;
        virtual ~List(){};
};

class outOfRange;
class badSize;

class outOfRange:public exception {
    public:
        const char* what()const throw() {
            return "ERROR! OUT OF RANGE.\n";
        }
};
class badSize:public exception {
    public:
        const char* what()const throw() {
            return "ERROR! BAD SIZE.\n";
        }
};

#endif

linkList.h

#ifndef _LINKLIST_H_
#define _LINKLIST_H_

template<class elemType>
class linkList:public List<elemType> {
    private:
        struct Node {
            public:
                elemType data;
                Node *next;
                Node(const elemType value,Node *p = NULL) {
                    data = value;
                    next = p;
                }
                Node(Node *p = NULL) {
                    next = p;
                }
        };
        Node *head;
        Node *tail;
        int curLength;
        Node *getPosition(int i)const;
        
        void traverseRecursive(Node *p);
        void traverseNonRecursive();
    public:
        linkList();
        ~linkList();
        void clear();
        
        bool empty()const {
            return head->next==NULL;
        }
        int size()const{
            return curLength;
        }
        void insert(int i,const elemType &value);
        void remove(int i);
        int search(const elemType &value)const;
        elemType visit(int i)const;
        void traverse()const;
        void headCreate();
        void tailCreate();
        void inverse();
        int prior(const elemType &value)const;
        linkList *Union(linkList<elemType> *lb);
        void outPut();
};

template<class elemType>
linkList<elemType>::linkList() {
    head = tail = new Node();
    curLength=0;
}

template<class elemType>
linkList<elemType>::~linkList() {
    clear();
    delete head;
}

template<class elemType>
void linkList<elemType>::clear() {
    Node *p,*tmp;
    p = head->next;
    while(p!=NULL) {
        tmp = p;
        p = p->next;
        delete tmp;
    }
    head->next = NULL;
    tail = head;
    curLength = 0;
}

template<class elemType>
typename linkList<elemType>::Node* linkList <elemType>::getPosition(int i)const { //因为是 private 所以不能直接调用 
    Node *p = head;
    int count = 0;
    if (i<-1 || i>curLength - 1)             //查找的合法位置为 [-1...n-1]
        return NULL;
    while (count <= i) {
        p = p->next;
        count++;
    }
    return p;                                //返回指向第 i结点的指针 指针类型 typename:Node*
}

template<class elemType>
void linkList<elemType>::insert(int i, const elemType &value) {
    Node *p,*q;
    if (i<0 || i>curLength)                  //合法的插入位置为 [0...n]
        throw outOfRange();
    p = getPosition(i - 1);                  //p时位序为 i的结点的前驱
    q = new Node(value, p->next);
    p->next = q;
    if (p == tail)tail = q;                  //插入点在表为,插入结点成为新的尾结点
    curLength++;
}

template<class elemType>
void linkList<elemType>::remove(int i) {
    Node *pre,*p;
    if (i<0 || i>curLength - 1)             //合法的删除位置为 [0...n-1]
        throw outOfRange();
    pre = getPosition(i - 1);
    p = pre->next;                          //p时真正待删除结点
    if (p == tail) {                        //待删除结点为尾结点,则修改尾指针
        tail = pre;
        pre->next = NULL;
        delete p;
    }
    else {                                  //删除结点 p并修改指针
        pre->next = p->next;
        delete p;
    }
    curLength--;
}

template<class elemType>
void linkList<elemType>::traverse()const {
    Node *p = head->next;
    cout << "traverse:";
    while (p != NULL) {
        cout << p->data << " ";
        p = p->next;
    }
    cout << endl;
}

template<class elemType>
int linkList<elemType>::search(const elemType &value)const {
    Node *p = head->next;
    int count = 0;                           //首元结点的位序为 0
    while (p != NULL && p->data != value) {
        p = p->next;
        count++;
    }
    if (p == NULL)return -1;                 //查找失败返回 -1,这里-1并非头结点
    else return count;
}

template<class elemType>
elemType linkList<elemType>::visit(int i)const {
    Node *p = head->next;
    int count = 0;                           //首元结点位序为 0
    if (i<0 || i>curLength - 1)              //合法的访问位置为 [0...n-1]
        throw outOfRange();                  //当结点不存在时,抛出异常
    while (count < i) {
        p = p->next;
        count++;
    }
    return p->data;
}

template<class elemType>
void linkList<elemType>::headCreate() {
    Node *p;
    elemType value, flag;
    cout <<"input elements,ended with:";
    cin >> flag;                             //输入结束标志
    
    while (cin >> value, value != flag)
    {
        p = new Node(value, head->next);
        head->next = p;                      //结点 p插入到头结点的后面
        if (head == tail)tail = p;           //原链表为空,则节点 p是尾结点
        curLength++;
    }
}

template<class elemType>
void linkList<elemType>::tailCreate() {
    Node *p;
    elemType value, flag;
    cout << "input elements,enden whit:";
    cin >> flag;                            //输入结束标志

    while (cin >> value, value != flag)
    {
        p = new Node(value, NULL);
        tail->next = p;                     //结点 p插入到尾结点的后面
        tail = p;                           //结点 p成为新的表尾
        curLength++;
    }
}

template<class elemType>
void linkList<elemType>::inverse() {
    Node *p,*tmp;
    p = head->next;                         // p为工作指针指向首元结点
    head->next = NULL;                      //构成只有一个头结点的空链表
    if (p) tail = p;                        //原首元结点将变成表为
    while (p)
    {
        tmp = p->next;                      //保存当前处理结点 p的后继
        p->next = head->next;
        head->next = p;                     //结点 p插入到头结点的后面
        p = tmp;
    }
}

template<class elemType>
int linkList<elemType>::prior(const elemType &value)const {
    Node *p = head->next;                   // p是工作指针指向首元结点
    Node *pre = NULL;                       // pre指向 p的前驱结点
    int count = -1;                         //-1表示首元结点无前驱
    while (p && p->data != value) {
        pre = p;                            //前驱指针后移
        p = p->next;                        //指向下个待处理结点
        count++;
    }
    if (p == NULL)return-1;                 //查找失败返回 -1,这里 -1并非头结点
    else return count;                      //查找成功,count为元素的位序
}

template<class elemType>
linkList<elemType> *linkList<elemType>::Union(linkList<elemType> *lb) {
    Node *pa,*pb,*pc;                       //分别是链表 la,lb,lc的工作指针
    linkList<elemType> *lc =
        this;                               // lc利用 la空间,将 lb合并进来
    pa = head->next; head->next = NULL;     // la表头结点的指针域置为Null,构成空链表
    pb = (lb->head)->next; (lb->head)->next = NULL;         // lb表头结点的指针域置为 NULL,构成空链表
    pc = lc->head;                          //为节省空间 lc表直接利用 la表头结点
    while (pa && pb) {                      // la和 lb均为非空
        if (pa->data <= pb->data) {         // pb所指结点尾插法插入 lc表
            pc->next = pa; pc = pa; pa = pa->next;
        }
        else {                              // pb所指结点尾插法插入 lc表
            pc->next = pb; pc = pb; pb = pb->next;
        }
    }
    if (pa) {                               //若 pa未到尾,将 pc所指向 pa
        pc->next = pa;
        lc->tail = lb->tail;                //修改尾指针
    }
    else {
        pc->next = pb;                      //若 pb未到尾,将 pc指向 pb
        lc->tail = lb->tail;                //修改尾指针
    }
    lc->curLength = curLength + lb->curLength;
    delete lb;
    return lc;
}

template<class elemType>
void linkList<elemType>::outPut() {
    cout << "递归:";
    traverseRecursive(head->next); cout << endl;
    cout << "非递归:";
    traverseNonRecursive(); cout << endl;
}

template<class elemType>
void linkList<elemType>::traverseRecursive(Node *p) {
    if (p) {
        cout << p->data << " ";             //输出结点的值
        traverseRecursive(p->next);         //尾递归调用
    }
}
//顺序表输出单链表结点数据的非递归算法:
template<class elemType>
void linkList<elemType>::traverseNonRecursive() {
    Node *tmp = head->next;
    while (tmp != NULL) {
        cout << tmp->data << " ";           //输出结点的值
        tmp = tmp->next;                    //向里一层修改变量值
    }
    cout << endl;
}
#endif

All.cpp

#include <bits/stdc++.h>
using namespace std;
#include "C:\Users\14805\Desktop\LIST.h"
#include "C:\Users\14805\Desktop\linkList.h"

template<class T>
void testList(linkList<T>* p)
{
    if (p->empty())cout << "empty list\n";
    cout << " test insert:\n";
    int n, i;
    T val;
    cout << "input number of nodes;:\n";
    cin >> n;                                                       //输入结点总数
    cout << "input each node's insertion position and value:\n";
    while (n > 0)                                                   //测试插入
    {
        cin >> i;                                                   //输入结点插入位置的下标
        cin >> val;                                                 //输入结点的值
        try
        {
            p->insert(i, val);                                      //插入
        }
        catch (outOfRange)
        {
            cerr << "error,catch outOfRange\n";
        }
        n--;
    }
    p->traverse();                                                  //测试遍历
    cerr << "curLength:" << p->size() << endl;                      //输出表长

    cout << "test inverse:\n";
    p->inverse();                                                  //测试逆置 
    p->traverse();                                                 //测试遍历

    cout << "test search:\n";                                      //测试查找
    cout << "input the value:\n";
    cin >> val;                                                    //输入要查找的元素值
    cout << "the position of" << val << "is:" << p->search(val) << endl;    //查找

    cout << "test the delete:\n";                                  //测试删除
    cout << "input the position:\n";
    cin >> i;                                                      //输入删除位置
    try
    {
        p->remove(i);                                              //删除
    }
    catch (outOfRange)
    {
        cerr << "error, catch outOfRange.\n";
    }
    p->traverse();                                                 //测试遍历

    cout << "test visit:\n";                                       //测试访问
    cout << "input the position[0...n-1]:\n";
    cin >> i;                                                      //输入要访问的元素
    try
    {
        cout << "position:" << i << ":" << p->visit(i) << endl;    //访问
    }
    catch (outOfRange)
    {
        cerr << "error, catch outOfRange.\n";
    }
}

template<class T>
void testLinkCreate(linkList<T>* lk)
{
    cout << "test headCreate:\n";
    lk->headCreate();                                              //测试头插法
    lk->traverse();

    lk->outPut();

    cout << "test tailCreate:\n";
    lk->tailCreate();                                              //测试尾插法
    lk->traverse();
}

int main()
{
    linkList<int>* lk;                                             //创建一个单链表

    lk = new linkList<int>();

    testList(lk);                                                  //测试单链表

    system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值