1.链表简介
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。(百度百科)
2.链表的基本操作
-
创建链表
首先要创建链表节点结构体,链表的单个节点由两部分构成,即数据域与指针域。数据域用来存储数据,指针域存储后继的地址。(本博文仅讨论单向链表)
创建链表时,需要声明一个头节点。一般情况下,头节点不含数据,并且指向存储第一个数据的节点。 -
插入数据
对链表进行数据插入操作时,需要分配一个新的存储空间存储新的节点,并且使插入位置的前驱指向新节点,新节点指针域指向后继。如图所示:
-
删除数据
对链表中的数据进行删除时,只需要其前驱直接指向后继,打断被删除节点与后继的连接,并释放该节点即可,如图所示:
-
遍历
遍历链表的重要依据就是其指针域指向其后继,只需访问每个节点指针域指向节点即可完成遍历。
3.链表的C++实现
- 构造链表类以及节点结构体
template<class DataType>
struct node //节点
{
DataType data; //数据域
node<DataType> *next; //指针域
};
template<class DataType>
class LinkList //链表类
{
public:
LinkList(); //无参数构造
LinkList(DataType a[], int n); //按数组构造
~LinkList(); //析构
int length(); //返回长度
DataType get(int i); //按位查值
int locate(DataType x); //按值查位
void insert(int i, DataType x); //插值
void del_loc(int i); //按位删值
void del_data(DataType x); //按值删值
void clear(); //清空
private:
node<DataType> *head; //头节点
};
- 构造方法
template<class DataType>
LinkList<DataType>::LinkList()
{
head = new node<DataType>; //为头节点分配内存空间完成构造
head->next = NULL;
cout << "LinkList Constructed" << endl;
}
template<class DataType>
LinkList<DataType>::LinkList(DataType a[], int n)
{
head = new node<DataType>;
head->next = NULL;
for (int i = n - 1;i >= 0;i--) //依次头插
{
node<DataType> *s = new node<DataType>;
s->data = a[i];
s->next = head->next;
head->next = s;
}
cout << "LinkList Constructed" << endl;
}
- 析构方法
template<class DataType>
LinkList<DataType>::~LinkList()
{
while (head != NULL) //依次释放空间
{
node<DataType>* q = head;
head = head->next;
delete q;
}
cout << "LinkList Distructed!" << endl;
}
- 返回长度
template<class DataType>
int LinkList<DataType>::length()
{
node<DataType>* p = head->next; //通过遍历求长度
int cnt = 0;
while (p != NULL)
{
p = p->next;
cnt++;
}
return cnt;
}
- 按位查值与按值查位
template<class DataType>
DataType LinkList<DataType>::get(int i) //按位查值
{
node<DataType>* p = head->next;
int cnt = 1;
while (p != NULL && cnt < i) //遍历到需要查找的位置
{
p = p->next;
cnt++;
}
if (p == NULL)
throw "Location Error!";
else
return p->data;
}
template<class DataType>
int LinkList<DataType>::locate(DataType x) //按值查位
{
node<DataType> *p = head->next;
int cnt = 1;
while (p != NULL) //遍历查找需要查的值
{
if (p->data == x)
return cnt;
p = p->next;
cnt++;
}
return 0;
}
- 插入
template<class DataType>
void LinkList<DataType>::insert(int i, DataType x)
{
node<DataType> *p = head;
int cnt = 0;
while (p != NULL && cnt < i - 1)
{
p = p->next;
cnt++; //遍历到要插入的位置
}
if (p == NULL)
throw "Location Error!";
else
{
node<DataType> *s = new node<DataType>;
s->data = x;
s->next = p->next; //这是关键语句,时新节点指向后继
p->next = s; //使前驱指向新节点
}
}
- 按位删值与按值删值
template<class DataType>
void LinkList<DataType>::del_loc(int i) //按位删值
{
node<DataType> *p = head;
int cnt = 0;
while (p != NULL && cnt < i - 1) //遍历到需要删除的节点
{
p = p->next;
cnt++;
}
if (p == NULL || p->next == NULL)
throw "Location Error!";
else
{
node<DataType> *q = p->next;
// int x = q->data;
p->next = q->next; //使该节点前驱直接指向后继
delete q; //释放空间
}
}
template<class DataType>
void LinkList<DataType>::del_data(DataType x)
{
node<DataType> *q = head->next;
int index = 1;
while(q != NULL) //相似的方法,遍历删除每一个符合条件的节点
{
if(q->data == x)
{
q = q->next;
node<DataType> *p = head;
for(int i = 1;i < index;i++)
{
p = p->next;
}
node<DataType> *r = p->next;
p->next = r->next;
delete r;
}
else
{
index++;
q=q->next;
}
}
}
- 清空链表
template<class DataType>
void LinkList<DataType>::clear()
{
while (head != NULL) //依次释放空间
{
node<DataType>* q = head->next;
head = head->next;
delete q;
}
cout << "LinkList cleared!" << endl;
}
- 调试函数
void LinkList_debug()
{
LinkList<int> a;
int sw;
cout << "LinkList Options:\n1.Insert data\n2.Delete data by location\n3.Delete data by value\n4.Find data by location\n5.Find location by data\n6.Get the length\n7.Clear the list\n8.Print the list\n9.Exit\n";
while (cin >> sw)
{
if (sw == 1)
{
int loc,da;
cout << "Please input the location and data: ";
cin >> loc >> da;
a.insert(loc,da);
}
else if (sw == 2)
{
int loc;
cout << "Please input the location: ";
cin >> loc;
a.del_loc(loc);
}
else if (sw == 3)
{
int x;
cout << "Please input the data: ";
cin >> x;
a.del_data(x);
}
else if (sw == 4)
{
int loc,x;
cout << "Please input the location: ";
cin >> loc;
x = a.get(loc);
cout << x << endl;
}
else if (sw == 5)
{
int loc,x;
cout << "Please input the data: ";
cin >> x;
loc = a.locate(x);
cout << loc << endl;
}
else if (sw == 6)
{
cout << a.length() << endl;
}
else if (sw == 7)
{
a.clear();
}
else if (sw == 8)
{
for(int i = 1;i <= a.length();++i)
cout << a.get(i) << " ";
cout << endl;
}
else
{
break;
}
cout << "LinkList Options:\n1.Insert data\n2.Delete data by location\n3.Delete data by value\n4.Find data by location\n5.Find location by data\n6.Get the length\n7.Clear the list\n8.Print the list\n9.Exit\n";
}
}
4.小结
相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
总提纲:《数据结构》期末提纲小结