数据结构-链表(链表的基本实现C++)

​线性表是最常用而且简单的一种数据结构,一个线性表是n个数据元素的有限序列。
当线性表需要频繁查找,较少插入和删除时,通常采用顺序存储结构,若需要频繁插入和删除,通常采用基于链表的形式;当线性表的元素个数变化较大或不确定时,最好用链表,这样不需要考虑存储空间大小问题,当事先知道线性表的大小长度,用顺序存储结构效率会高一些。

1.线性表

1、线性表的顺序表示和实现顺序表,基于数组的一种实现,一组地址连续的存储单元。顺序表可以是动态的,也可以是静态的,“静态”就是一开始就知道表容量,并且这个容量在之后无法被更改;“动态”就是能够动态的改变表的容量,实现上基于动态内存分配。数组大小有两种方式指定,一是静态分配,二是动态扩展。

优点:查找很方便

缺点:插入元素、删除元素比较麻烦,时间复杂度 O(n)

#include <iostream>
#include <cstdlib>
#include "assert.h"
​
const int MAXSIZE = 512;
​
template <class T>
class SeqList {
public:
  SeqList() { length = 0; }  //默认构造函数
  SeqList(const T a[], int n); //含参构造函数
  int GetLength() { return length; }  //获取长度
  void Insert(int i, T x);  //插入元素
  T Delete(int i); //删除元素
  T Get(int i);  //通过下标获取元素
  int Locate(T x);  //通过元素值查找元素
  void Print();  //打印输出
private:
  int length;
  T data[MAXSIZE];
​
};
template <class T>
SeqList<T>::SeqList(const T a[], int n) {
  if (n > MAXSIZE) {
    throw "超过顺序表的最大长度";
  }
  for (int i = 0; i < n; i++) {
    data[i] = a[i];
  }
  length = n;
}
​
template <class T>
void SeqList<T>::Insert(int i, T x) {
  if (length > MAXSIZE) throw "上溢异常";
  if (i<0 || i>length) throw "位置异常";
  for (int j = length; j >= i; j--) {
    data[j] = data[j - 1];
  }
  data[i] = x;
  length++;
}
​
template <class T>
T SeqList<T>::Delete(int i) {
  if (length == 0) throw "下溢异常";
  if (i<0 || i>=length) {
    throw "位置异常";
  }
  T x = data[i];
  for (int j = i; j < length - 1; j++) {
    data[j] = data[j + 1];
  }
  length--;
  return x;
}
​
template <class T>
T SeqList<T>::Get(int i) {
  if (0 == length) throw"上溢异常";
  if (i<0 || i>=length) {
    throw "查找位置非法";
  }
  return data[i];
}
​
template <class T>
int SeqList<T>::Locate(const T x) {
  for (int i = 0; i < length; i++) {
    if (x == data[i])
      return i;
  }
  return 0;
}
​
template <class T>
void SeqList<T>::Print() {
  cout << "遍历线性表数据元素:" << endl;
  for (int i = 0; i < length; i++) {
    cout << data[i] << " ";
  }
  cout << endl;
}
2、线性表的链式表示和实现

顺序表的链式表示形式又分为了:单链表、双向链表、单循环链表、双向循环链表几种。

优点:插入或删除元素时很方便,使用灵活,存储空间利用率高。

缺点:存储密度小(<1),查找和修改需要遍历整个链表。

单链表

代码实现:

#include <iostream>
#include <cstdlib>
#include "assert.h"
​
template <class T>
class LNode
{
public:
  T data;
  LNode<T>* next;
};
​
template <class T>
class LinkList {
public:
  LinkList() { head = nullptr; }
  ~LinkList();
  bool clear();
  bool empty() { return head == nullptr; };
  int length();
  bool getElem(int i, T& t);
  int locateElem(const T& t);
  bool priorElem(const T& t_cur, T& t_pre);
  bool nextElem(const T& t_cur, T& t_next);
  bool insert(int i, T t);
  bool term(int i, T t);
  LNode<T>* reverse();
​
private:
  LNode<T>* head;
};
​
//清空函数
template <class T>
bool LinkList<T>::clear() {
  LNode<T> *p = head;
  while (head) {
    p = head;
    head = head->next;
    delete(p);
  }
  return true;
}
​
//析构函数
template <class T>
LinkList<T>::~LinkList() {
  clear();
}
​
//获取链表长度
template <class T>
int LinkList<T>::length() {
  LNode<T>* p = head;    //不能直接用head循环
  int len = 0;
  while (p != nullptr) {
    len++;
    p = p->next;
  }
  return len;
}
​
//获取指定位置元素
template <class T>
bool LinkList<T>::getElem(int i, T &t) {
  int j = 0;
  LNode<T>* p = head;
  while (j < i && p) {
    p = p->next;
    j++;
  }
  if (p == nullptr) return false;
  t = p->data;
  return true;
}
​
//查找元素位置
template <class T>
int LinkList<T>::locateElem(const T& t) {
  int loc = 0;
  LNode<T>* p = head;
  while (p->data!=t && p) {
    p = p->next;
    loc++;
  }
  if (p->data == t) return loc;
  else return -1;
}
​
//获取前驱节点
template <class T>
bool LinkList<T>::priorElem(const T& t_cur, T& t_pre) {
  LNode<T>* p = head;
  if (p->data == t_cur) return false;
  while (p->next->data != t_cur && p->next) {
    p = p->next;
  }
  if (p->next->data == t_cur) {
    t_pre = p->data;
    return true;
  }
   
  return false;
}
​
//获取后继节点
template <class T>
bool LinkList<T>::nextElem(const T& t_cur, T& t_next) {
  LNode<T>* p = head;
  if (head == nullptr || head->next == nullptr) return false;
  while (p->next != nullptr) {
    if (p->data == t_cur)
    {
      t_next = p->next->data;
      return true;
    }
    else
      p = p->next;
  }
  return false;
}
​
template <class T>
bool LinkList<T>::insert(int i, T t) {
  LNode<T>* p = head;
  LNode<T>* s = head;
  int loc = 0;
  if (i == 0) {
    s = (LNode<T>*)malloc(sizeof(LNode<T>));
    s->data = t;
    s->next = p;
    head = s;
    return true;
  }
  while (p && loc < i - 1) {
    p = p->next;
    loc++;
  }
  if (p == nullptr)
    return false;
  s = (LNode<T>*)malloc(sizeof(LNode<T>));
  s->data = t;
  s->next = p->next;
  p->next = s;
  return true;
}
​
//删除指定位置元素
template <class T>
bool LinkList<T>::term(int i, T t) {
​
  LNode<T>* p = head;
  int loc = 0;
  if (i == 0) {
    t = head->data;
    head = head->next;
    delete p;
    p = nullptr;
    return true;
  }
  while (p && loc < i - 1) {
    loc++;
    p = p->next;
  }
  if (p == nullptr)
    return false;
​
  LNode* s;
  s = p->next;
  p->next = p->next->next;
  t = s->data;
  delete s;
  s = NULL;
  return true;
}
​
//反转链表
template <class T>
LNode<T>* LinkList<T>::reverse() {
  if (head == nullptr || head->next == nullptr) return head;
  LNode<T> *p = head, *q = head->next, *r;
  head->next = nullptr;
  while (q) {
    r = q->next;
    q->next = p;
    p = q;
    q = r;
  }
  head = p;
  return head;
}
​
3.双向链表

代码实现:

#include <iostream>
#include <cstdlib>
#include "assert.h"
​
template <class T>
class DNode
{
public:
  DNode<T> *next;
  DNode<T> *prev;
  T data;
};
​
template <class T>
class List
{
public:
  List();//默认构造函数
  List(const List& ln);//拷贝构造函数
  ~List();//析构函数
  void add(T e);//向链表添加数据
  void remove(T index);//移除某个结点
  T find(int index);//查找结点
  bool empty();//判断是否为空
  int size();//链表长度
  void print();//显示链表
  void print_reverse();//链表反向显示
  void clear();//删除全部结点
private:
  DNode<T> *head;
  DNode<T> *tail;
  int length;
};
​
​
//默认构造函数
template <typename T>
List<T>::List()
{
  head = new DNode<T>;
  tail = new DNode<T>;
  head->next = tail;
  head->prev = nullptr;
  tail->next = nullptr;
  tail->prev = head;
  length = 0;
}
​
//拷贝构造函数
template <typename T>
List<T>::List(const List &ln)
{
  head = new DNode<T>;
  head->prev = nullptr;
  tail = new DNode<T>;
  head->next = tail;
  tail->prev = head;
  length = 0;
  DNode<T>* temp = ln.head;
  while (temp->next != ln.tail)
  {
    temp = temp->next;
    tail->data = temp->data;
    DNode<T> *p = new DNode<T>;
    p->prev = tail;
    tail->next = p;
    tail = p;
    length++;
  }
  tail->next = nullptr;
}
​
//析构函数
template <typename T>
List<T>::~List()
{
  if (length == 0)
  {
    delete head;
    delete tail;
    head = nullptr;
    tail = nullptr;
    return;
  }
  while (head->next != nullptr)
  {
    DNode<T> *temp = head;
    head = head->next;
    delete temp;
  }
  delete head;
  head = nullptr;
}
​
//向链表添加数据
template <typename T>
void List<T>::add(T e)
{
  DNode<T>* temp = this->tail;
  tail->data = e;
  tail->next = new DNode<T>;
  DNode<T> *p = tail;
  tail = tail->next;
  tail->prev = p;
  tail->next = nullptr;
  length++;
}
//查找结点
template <typename T>
T List<T>::find(int index)
{
  if (length == 0)
  {
    std::cout << "List is empty";
    return NULL;
  }
  if (index >= length)
  {
    std::cout << "Out of bounds";
    return NULL;
  }
  int x = 0;
  DNode<T> *p;
  p = head->next;
  while (p->next != nullptr && x++ != index)
  {
    p = p->next;
  }
​
  return p->data;
}
//删除结点
template <typename T>
void List<T>::remove(T index)
{
  if (length == 0)
  {
    std::cout << "List is empty";
    return;
  }
  DNode<T> *p = head;
  while (p->next != nullptr)
  {
    p = p->next;
    if (p->data == index)
    {
      DNode<T> *temp = p->prev;
      temp->next = p->next;
      p->next->prev = temp;
      delete p;
      length--;
      return;
    }
  }
}
//删除所有结点
template <typename T>
void List<T>::clear()
{
  if (length == 0)
  {
    return;
  }
  DNode<T> *p = head->next;
  while (p != tail)
  {
    DNode<T>* temp = p;
    p = p->next;
    delete temp;
  }
  head->next = tail;
  tail->prev = head;
  length = 0;
}
​
//判断是否为空
template <typename T>
bool List<T>::empty()
{
  if (length == 0)
  {
    return true;
  }
  else {
    return false;
  }
}
//链表长度
template <typename T>
int List<T>::size()
{
  return length;
}
//输出链表
template <typename T>
void List<T>::print()
{
  if (length == 0)
  {
    std::cout << "List is empty" << std::endl;
    return;
  }
  DNode<T> *p = head->next;
  while (p != tail)
  {
    std::cout << p->data << " ";
    p = p->next;
  }
  std::cout << std::endl;
}
//反向输出链表
template <typename T>
void List<T>::print_reverse()
{
  if (length == 0)return;
  DNode<T> *p = tail->prev;
  while (p != head)
  {
    std::cout << p->data << " ";
    p = p->prev;
  }
  std::cout << std::endl;
}

测试类main.cpp:

#include "CList.hpp"
#include <iostream>
using namespace std;
int main(int argc, char**argv)
{
​
  cout << "***顺序表***" << endl;
​
  SeqList<int> seqList;
  int val = -1;
  int iLocate = -1;
  for (int i = 0; i < 10; i++)
  {
    seqList.Insert(i, i+1);
  }
  seqList.Print();
  val = seqList.Get(3);
  cout << "seqList.Get(3): " << val << endl;
​
  val = seqList.Delete(2);
  cout << "seqList.Delete(2): " << val << endl;
  seqList.Print();
​
  iLocate = seqList.Locate(5);
  cout << "seqList.Locate(5): " << val << endl;
​
  cout << endl;
  cout << "***单链表***" << endl;
​
  int a = 0;
  int *p = &a;
  LinkList<int> linkList;
  linkList.insert(0, 5);
  linkList.insert(1, 4);
  linkList.insert(2, 12);
  linkList.insert(3, 5);
  linkList.insert(3, 6);
  linkList.insert(1, 7);
  cout << "链表长度" << linkList.length() << endl;
  cout << "各个元素的值是: ";
  for (int i = 0; i < linkList.length(); i++)//遍历该链表
  {
    if (linkList.getElem(i, *p))
      cout << *p << "   ";
  }
  cout << endl;
  cout << "反转后各个元素的值是: ";
  LNode<int>* re_linkList = linkList.reverse();
  while (re_linkList)
  {
    cout << re_linkList->data << "   ";
    re_linkList = re_linkList->next;
  }
  cout << endl;
  cout << endl;
  cout << "***双向链表***" << endl;
​
  List<int> list;
  list.add(6);
  list.add(443);
  list.add(767);
  list.add(56);
​
  List<int> list2(list);
  list2.print_reverse();
  list2.print();
  std::cout << "list2.size(): " << list2.size() << std::endl;
  std::cout << "list2.find(2): " << list2.find(2) << std::endl;
  list2.remove(443);
  list2.print();
​
  system("pause");
  return 0;
}

执行结果:

博客编写不易,求点赞收藏,还存在链表操作不当的问题,对链表的空间申请和存储情况还理解不到位。

  • 15
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值