在数据结构的学习中,链表可以说是我们最早接触到的一种数据结构了(字符串和数组除外),在各大数据结构及算法书中,如CLRS,或者是清华大学版数据结构中,链表也是最早介绍的一种数据结构。它实现起来比较简单,同时能实现一些我们平时用数组难以实现的功能,很适合我们入手数据结构。下面我们简单来看看链表中最简单的一种,单链表的结构及其实现。
链表是一种线性的数据结构,它由结点构成,每个结点由数据域和指针域组成。其中,除了头结点外和尾结点外,每个结点都有一个前驱及后继。其中结点的数据域储存数据,指针则指向后继结点。如图所示
链表相对于数组,它的有点在于能够快速地增加或者删除元素,只需要改变指针指向,无需移动元素。其增加元素删除元素的时间复杂度是O(1),而数组的时间复杂度为O(n)。另外,链表相比之于数组其劣势在于无法随机访问元素,若要访问链表中的某一位置的元素,必须从表头开始遍历,时间复杂度为O(n),相比之下数组可以通过下标直接索引,时间复杂度仅为O(n)。另外,由于每个链表结点中,既储存了数据,又储存了指针,所以链表的存储密度小于1。(存储密度 = (结点数据本身所占的存储量)/(结点结构所占的存储总量))
下面是简单的单链表的c++源代码实现:
首先是LinkList.h的头文件,其定义了链表支持的方法。
using namespace std;
struct ListNode
{
int val; //数据域
ListNode *next; //指针域
ListNode(int x) :val(x), next(NULL){}
};
class List
{
private:
ListNode* head;
int len;
public :
List(); //构造函数
~List(); //析构函数
int length(); //返回链表长度
void display(); //输出链表
void push_back(int val); //在链表末尾插入新元素
void insert(int val, int pos); //在链表指定位置插入新元素
bool empty(); //判断链表是否为空
void erase(int pos); //删除指定位置的元素
bool search(int val); //查询值为val的元素
};
接下来是cpp文件,是链表方法的实现:
// List_1.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "LinkList.h"
#include <iostream>
using namespace std;
//链表构造函数
List::List()
{
head = NULL;
len = 0;
}
//链表的析构函数,遍历链表并且删除每个结点
List::~List()
{
ListNode *p = NULL;
if (head)
{
p = head;
while (len)
{
head = p->next;
delete p;
p = head;
--len;
}
}
}
//返回链表长度
int List::length()
{
return len;
}
//判断链表是否为空
bool List::empty()
{
return len == 0;
}
//链表末尾插入。
void List::push_back(int val)
{
//若链表为空,则需要生成一个头结点
if (head == NULL)
head = new ListNode(val);
else
{
ListNode *p = head;
while (p->next)
p = p->next;
p->next = new ListNode(val);
}
++len;
}
void List::display()
{
ListNode *p = head;
while (p)
{
cout << p->val << " ";
p = p->next;
}
cout << endl;
delete p;
}
//在第pos位插入一个新的元素
void List::insert(int val, int pos)
{
//插入位置必须为1到len+1范围内
if (pos > len + 1||pos<1)
{
cout << "超出链表范围" << endl;
return;
}
//若在链表头部插入,则需要更改头结点
else if (pos == 1)
{
ListNode *s = new ListNode(val);
s->next = head;
head = s;
++len;
return;
}
ListNode *p = head;
for (int i = 0; i < pos - 2; ++i)
p = p->next;
ListNode *s = new ListNode(val);
s->next = p->next;
p->next = s;
++len;
}
//判断一个元素是否在链表内
bool List::search(int val)
{
ListNode *p = head;
while (p)
{
if (p->val == val)
return true;
p = p->next;
}
delete p;
return false;
}
//删除pos位的元素
void List::erase(int pos)
{
//删除元素的位置必须大于0且小于等于链表长度
if (pos > len||pos<1)
{
cout << "超出范围" << endl;
return;
}
//若在顶端删除,则需要更改头结点
else if (pos == 1)
{
ListNode *s = head;
head = s->next;
delete s;
--len;
return;
}
//链表中间删除
ListNode *p = head;
for (int i = 0; i < pos - 2; ++i)
p = p->next;
ListNode *s = p->next;
p->next = s -> next;
delete s;
--len;
}
int _tmain(int argc, _TCHAR* argv[])
{
List l = List();
//测试插入功能
l.insert(1,1);
l.insert(0, 1);
l.insert(-1, 1);
l.display();
//测试删除功能
l.erase(1);
l.display();
//测试末尾插入
l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_back(4);
l.display();
//测试搜索功能
cout << l.search(1) << endl;
l.display();
//测试链表长度函数
cout << l.length() << endl;
return 0;
}