单链表

线性链表

线性链表的定义

用一组任意的存储单元(可以连续,也可以不连续)存储线性表的数据元素。存储的数据只是逻辑上的相邻,不一定要求物理上的相邻。每一个存储的数据元素称为节点,一个节点包括两个域:其中存储数据元素的叫数据域;存储直接后继存储位置的域称为指针域。指针域中存储的信息称作指针。n个结点链接称为一个链表,也就是线性表


易混淆概念

  1. 首元结点:链表中存储第一个数据元素的结点。
  2. 头结点:在首元结点之前附加的一个结点,其指针指向首元结点。
  3. 头指针:指向链表中第一个结点的指针。若有头结点,则指向头结点;若没有,直接指向首元结点。

头结点的作用

  1. 便于首元结点的处理
    增加了头结点,就可以直接通过保存在头结点中的指针来对首元结点进行操作(就像其他元素一样),无需进行特殊处理。
  2. 便于空表和非空表的统一处理
    无论链表是否为空,头指针都是指向头结点的非空指针。要判定链表是否为空,只需要判断头结点的指针域是否为空就可以。

基本操作的思路

  • 初始化
  1. 生成新节点作为头结点,用头指针L指向头结点。
  2. 头结点的指针域置空。
  • 向前插入元素
  1. 生成一个新结点*s
  2. 输入元素值赋给新结点*s的数据域
  3. 将新结点*s插入到头结点之后
  • 向后插入元素
  1. 生成一个新结点*s
  2. 输入元素值赋给新结点*的数据域
  3. 初始化一个定位指针*p,遍历后指向尾结点
  4. 将新结点*p插入到尾结点之后
  • 在中间插入元素(前插)
  1. 生成一个新结点*s
  2. 输入元素值赋给新结点*s的数据域
  3. 查找结点ai-1并将指针p指向结点ai
  4. 将结点*s的指针用户指向结点ai
  5. 将结点*p的指针域指向新结点*s
  • 删除某元素
  1. 让定位指针p指向结点ai-1
  2. 新建指针临时保存待删除结点ai的地址,以备释放
  3. 将结点*p的指针域指向ai+1
  4. 释放结点ai的空间

基本操作的具体实现

SingleLinkList.h

#pragma once
#define status bool
#define OK true
#define ERROR false
#define YES true
#define NO false

template<typename DType>
class Node {
public :
        DType data;
        Node * next;
};


template<typename DType>
class CSingleLinkList {
private:
        Node<DType> *phead;   //链表头指针
        Node<DType> *head;    //头结点
public:
        CSingleLinkList();   //构造函数
        ~CSingleLinkList();
public:
        //初始化链表
    status InitSList();
        //获取链表长度
        int GetLength();
        //前插结点
        status FrontInsert(DType data);
        //后插结点
        status BackInsert(DType data);
        //在指定位置向前插入结点
        status InsertByOrder(int order, DType);
       //获取指定序号的元素值
        status GetElemByOrder(int order, DType &receiver);
        //查找指定元素的地址,找不到就返回空地址
        Node<DType>* GetLocByElem(DType target);
        //删除指定序号的结点
        status DelByOrder(int order);
        //打印链表
        void PrintList();

};

CSingelLinkList.cpp

#include<iostream>
#include"SingleLinkList.h"
using namespace std;


template<typename DType>
CSingleLinkList<DType>::CSingleLinkList() {
        cout << "链表创建成功" << endl;
        InitSList();
}

//初始化链表
template<typename DType>
status CSingleLinkList<DType>::InitSList() {
        head = new Node<DType>;
        if (head != NULL) {
               head->next = NULL;
               phead = head;
               return OK;
        }
        return  ERROR;
}


//获取链表长度
template<typename DType>
int CSingleLinkList<DType>::GetLength() {
        //新建追踪指针指向头结点
        Node<DType> *pTrack = this->head;    //直接用head也可以

        //记录长度
        int length = 0;
        //遍历链表开始计数
        /*if (!head->pnext) {
               cout << "head->pnext is null" << endl;
        }*/
        while (pTrack->next!= NULL) {
               //cout << pTrack->next;
               pTrack = pTrack->next;
               length++;
        }
        //cout << length;
        return length;
}



//前插入结点
template<typename DType>
status CSingleLinkList<DType>::FrontInsert(DType data) {
        //新建结点
        Node<DType> *p = new Node<DType>;
        //录入数据
        p->data = data;
        //令其指向头结点后一个
        p->next = head->next;
        //让头结点指向它
        head->next = p;
        return OK;
}



//后插结点
template<typename DType>
status CSingleLinkList<DType>::BackInsert(DType data) {
        //新建结点保存数据
        Node<DType> *p = new Node<DType>;
        p->data = data;
        //跟踪指针,指向头结点
        Node<DType> *pTrack = head;
        //遍历让其指向表尾
        while (pTrack->next != NULL) {
               pTrack = pTrack->next;
        }
        pTrack->next = p;
        p->next = NULL;
        return OK;
}



//在指定位置向前插入结点
template<typename DType>
status CSingleLinkList<DType>::InsertByOrder(int order, DType data) {
        if (order<1 || order>this->GetLength()) {
               return ERROR;
        }
        Node<DType>* pTrack = head;
        Node<DType>* q = new Node<DType>;
        q->data = data;
        int count = 0;
        //遍历到前驱结点
        while (count < order-1) {
               pTrack = pTrack->next;
               count++;
        }
        q->next = pTrack->next;
        pTrack->next = q;
        return OK;
}



//返回指定序号的元素值
template<typename DType>
status CSingleLinkList<DType>::GetElemByOrder(int order, DType &receiver) {
        int count = 0;  //记数器
        //获取数据用的指针
        Node<DType> *pGet = head;
        if (order<1 || order>this->GetLength()) {
               return ERROR;
        }
        while (count != order) {
               pGet = pGet->next;
               count++;
        }
        receiver = pGet->data;
        return OK;
}



//查找指定元素的地址(返回首个符合的)
template<typename DType>
Node<DType>* CSingleLinkList<DType>::GetLocByElem(DType target) {
        //跟踪指针
        Node<DType> *pTrack = head;
        while(pTrack!=NULL) {
               if (pTrack->data == target) {
                       return pTrack;
               }
               pTrack = pTrack->next;
        }
        return NULL;
}



//删除指定序号的结点
template<typename DType>
status CSingleLinkList<DType>::DelByOrder(int order) {
        int count = 0;
        Node<DType>* pTrack = head;
        if (order<1 || order>this->GetLength()) {
               return ERROR;
        }
        //找到被删除结点的前驱节点
        while (count < order-1) {
               pTrack = pTrack->next;
               count++;
        }
        //保存被删除节点,方便删除
        Node<DType>* tmp = pTrack->next;  
        //让前驱节点指向后驱结点
        pTrack->next = tmp->next;
        //释放被删除结点
        delete tmp;
        return OK;
}



//打印链表
template<typename DType>
void CSingleLinkList<DType>::PrintList() {
        if (this->GetLength() == 0) {
               cout << "链表为空!" << endl;
        }
       //指向首元结点,头结点不保存数据
       Node<DType>* pTrack = head->next;
        cout << "================打印链表===============" << endl;
       while (pTrack!=NULL) {
               cout << pTrack->data << " ";
               pTrack = pTrack->next;
        }
        cout << endl;
}


posted @ 2019-08-29 00:38  裏表異体  阅读(176)  评论(0编辑  收藏  举报