1.线性表
2.顺序表
基本定义
链表的定义:链表(linked list)结构是由若干个具有相同结构形式的、称为结点的变量用链地址连接而成的结构形式。其中,每个结点逻辑上由两部分组成的,即数据部分(data)和指示后继结点的变量或者是指针(next)。
链表的术语:指向表头指示起点的指针叫头指针(head)。称存储表的首元素a₁的结点为首元素结点。最后一个结点(尾节点)的后继指针为空值,表示其后续没有结点了。
存储方式
静态链表
如果用数组中的元素来存储元素的值和地址,则可以构成存储在数组中的链表。由于在程序运行中,数组一直存在,且其元素个数固定不变,因而称这种链表为静态链表。
定义如下:
template <class Typename>
struct node {
Typename data;
int next;
};
node<int> list[8];
动态链表
在许多情况下,由于事先难以估计存储结构中元素的个数,因此静态链表难以适用。在这种情况下,希望在程序的运行中,根据实际问题的需要临时、动态地分配存储空间,这就需要动态链表。动态链表中的每个结点就是在运行中所产生的动态变量。
定义如下:
template <class Typename>
struct node {
Typename data;
node *next;
};
运算实现
单向链表
运算实现
为了使插入、删除元素时的操作一致,增加一个头结点。
头文件:
#ifndef LIST_H
#define LIST_H
template <class Type>
struct node {
Type data;
node *next;
};
template <class Type>
class list {
public:
list();//构造函数初始化(C++11可以在类中初始化)
~list();//析构函数释放链表所有空间
void creat_list();
int length();//求链表长度
void get_element(const int i, Type &x);//按序号取元素
node<Type>* locate(const Type x);//按元素求地址
void insert(const int i, const Type x);//按序号插入元素
void delete_element(const int i);//按序号删除元素
node<Type>* get_head();//读取头结点指针
void show();//打印链表元素
void copy(list B);//复制B表的内容
private:
node<Type> *head;
};
template <class Type>
list<Type>::list() {
head = new node<Type>;
head->next = NULL;
}
template <class Type>
void list<Type>::creat_list() {
int x;
node<Type> *p = head;
cout << "输入序列:";
while (cin >> x) {
node<Type> *u = new node<Type>;
u->data = x;
u->next = NULL;
p->next = u;
p = p->next;
}
cin.clear();
cout << "创建列表成功!" << endl;
}
template <class Type>
int list<Type>::length() {
int count = 0;
if (head->next != NULL) {
node<Type> *u = head->next;
while (u != NULL) {
++count;
u = u->next;
}
}
return count;
}
template <class Type>
void list<Type>::get_element(const int i, Type &x) {
if (i > 0 && i < lenth() + 1) {
node<Type> *u = head->next;
for (int j = 1; j < i; ++j)
u = u->next;
x = u->data;
}
}
template <class Type>
node<Type>* list<Type>::locate(const Type x) {
node<Type> *u = head->next;
while (u->data != x&&u != NULL)
u = u->next;
return u;
}
template <class Type>
void list<Type>::insert(const int i, const Type x) {
if (i > 0 && i < length() + 1) {
node<Type> *u = new node<Type>;
node<Type> *v = head;
for (int j = 1; j < i; ++j)
v = v->next;
u->data = x;
u->next = v->next;
v->next = u;
}
}
template <class Type>
void list<Type>::delete_element(const int i) {
if (i > 0 && i < length() + 1) {
node<Type> *u = head;
for (int j = 1; j < i; ++j)
u = u->next;
u->next = u->next->next;
delete u->next;
}
}
template <class Type>
node<Type>* list<Type>::get_head() {
return head;
}
template <class Type>
void list<Type>::show() {
if (length()) {
cout << "序列:";
node<Type> *u = head->next;
while (u != NULL) {
cout << u->data << " ";
u = u->next;
}
cout << endl;
}
else cout << "空链表!" << endl;
}
template <class Type>
void list<Type>::copy(list B) {
node<Type> *pa = head;
node<Type> *pb = B.get_head()->next;
while (pa->next != NULL)
pa = pa->next;
while (pb != NULL) {
node<Type> *u = new node<Type>;
u->data = pb->data;
pa->next = u;
pa = pa->next;
pb = pb->next;
}
pa->next = NULL;
cout << "复制成功!" << endl;
}
template <class Type>
list<Type>::~list() {
for (int i = length(); i > 0; --i)
delete_element(i);
delete head;
}
#endif
应用实例
设计算法将链表B复制到链表A
源代码:
#include<iostream>
#include"list.h"
using namespace std;
int main() {
int x;
list<int> A, B;
A.creat_list();
B.creat_list();
A.copy(B);
A.show();
cin.get();
}
运行截图
单循环链表
如果将单向链表的表尾结点中的后继指针改为指向表头结点,就构成了单循环链表。
单循环链表可以不带头结点,其特点是可从任意元素结点出发搜索到其他各元素结点。
带尾指针的单循环链表
在许多情况下,要求链表能方便地搜索到表头和表尾结点。为此,可采用带尾指针的单循环链表结构。这类结构也可以不带头结点。
双向链表
如果希望能快速地求出任一链表结点的前驱和后继指针,则需要用到双链表结构。双链表中每个结点除了后继指针外,还增加了指向其前驱的指针。双链表也可以带头结点,也可以是循环的。
本文详细介绍了链表的基本定义,包括数据部分和指针部分,并探讨了链表的两种存储方式:静态链表和动态链表。接着,文章深入讲解了单向链表的运算实现,包括插入、删除操作,并给出了应用实例和代码示例。此外,还讨论了单循环链表、带尾指针的单循环链表以及双向链表的结构和特点。

1655

被折叠的 条评论
为什么被折叠?



