链表
我们定义每个节点的结构如下:
struct Node{
int Element;
struct Node* next;
};
每个节点都包含了元素和指向下一个结构的指针。通过这些指针可以将一个个节点串起来从而形成了一个链表。
链表的插入操作
在这里,我们想把temp节点插入在node节点的后面,
- temp->next = node->next; 先将temp的next指向node的下一个节点
- node->next = temp; 然后将node的next指向temp
必须按照上面的顺序。
链表的删除操作
这里我们想要删除node节点,此时必须找到node的前一个节点pre,然后使pre的next指向node的下一个节点
- pre->next = node->next
- free(node)
使用虚拟的头结点(dummy head node)
我们在设计链表的插入和删除操作时,要考虑到特殊的情况。
我们想把节点插入在第一个节点的前面应该怎么做?直接使temp->next=node,并将temp设置为头节点。我们想将第一个节点删除时,pre是不存在的,这时只需要将head->next设置为头结点。但是这样做常常需要额外的判断并另外写代码。我们可以给链表添加一个虚拟的头结点,使得插入和删除操作并不需要特别去考虑第一个节点的情况。
struct Node
{
int Element;
struct Node *next;
Node():Element(0),next(nullptr){}
Node(int x):Element(x),next(nullptr){}
};
class List
{
public:
struct Node *node;
List()
{
node = new Node(); //新建链表时,配置一个节点空间,并使node指向他,作为虚拟的头结点
}
//在位置p后面插入一个节点
void Insert(struct Node *p, int value)
{
struct Node *temp = new Node(value);
temp->next = p->next;
p->next = temp;
}
void Delete(struct Node*p)
{
struct Node *temp;
for (temp = node; temp != nullptr;temp=temp->next)
{
if(temp->next == p)
{
temp->next = p->next;
delete p;
return;
}
}
}
};
双向循环链表(Doubly Linked Circular Lists)
双向循环链表的节点定义
struct node
{
struct node* next;
struct node* prev; //多了一个指向前面一个节点的指针
int data;
};
多重链表
多重链表可以用来表示树,图等数据结构。
例如: 如果有一个大学有40000名学生和2500门课程。我们想列出某次选课后,选某一门课的所有学生,或是列出某个学生选的所有的课。
说明: 当然,一种方法是使用二维矩阵来表示,但这会浪费绝大多数存储空间(矩阵中绝大多数是0),因为课程选的人数有限,而学生选的课也不可能会达到2500.所以我们应该想办法使用多重链表来表示这一个稀疏矩阵。
不用指针实现链表
有些语言并不支持指针,我们可以使用数组的方式实现链表,好像又叫做cursor implementation
上面的链表使用到指针的地方有:
- 数据存储在一个结构中,这个结构中有一个next指针指向下一个结构
- 我们使用malloc和free来申请和释放内存空间
只需要将上面的两条用其他的方法模拟出来就能摆脱指针了。
维基百科里的例子:
如果链表里的节点是下面这样的结构,并注意,每一个节点都存储在一个数组中,next表示指向的下一个节点的数组下标。这样,我们将数组的index类比了节点的地址。
record Entry {
integer next; // index of next entry in array
integer prev; // previous entry (if double-linked)
string name;
real balance;
}
按照如下的方式新建一个数组实现的链表
integer listHead //存储链表的第一个结点在数组中的下标
Entry Records[1000] //所有节点
链表可以按如下的方式形成,-1作为链表的结束,listhead为链表的头结点:
链表的遍历方法:
i := listHead
while i ≥ 0 // loop through the list
print i, Records[i].name, Records[i].balance // print entry
i := Records[i].next //移到下一个节点