在《算法入门学习——第二章:选择排序》 中我们介绍了数组与链表,本篇将对于链表的基本原理加以详细说明,如下:
#include <iostream>
#include <cstring>
using namespace std;
//定义结构体link(其实就是链表啦)
struct link {
int elem;
struct link* next;
//每个link(链表)储存两个内容:elem——数据;next——指向下一个链表元素的指针
};
/***
要理解这串代码,首先要明白一个基础知识——指针函数
函数返回指针:返回值类型为指针类型
eg:link* initLink()为无参函数,其返回值类型为link*,即指针类型。
***/
//下面是一些实现链表操作的函数:
//功能1:建立一个有初始大小的链表
link* initLink() {
link* p = (link*)new link;
link* temp = p;//由于temp是p的指针,那么调用temp相当于调用p
for (int i = 1; i < 5; i++) {
link* a = (link*)new link;//建立一个临时链表元素a,因为a指针,故其存放着与p数据类型相同的地址
a->elem = i;//每个a.elem中储存着一个链表元素的数据
a->next = NULL;
/***每个a.next中储存着下一个链表元素的地址,
由于是建立新链表逐层递增建立,所以每一次创建的a都是当前链表中的最后一个元素
我们知道,最后一个元素的next没有指向,安全起见,赋值为null(无法访问的地址)***/
temp->next = a;//p.next=a:将临时创建的链表元素a加在p的最后一位
temp = temp->next;
/***注意:上述操作只连接起后面的链表元素,但如果没有起始地址用户还是无法访问链表
就像铁链一样,断开其中的任意一环,它都不是一个完整的链条,这里的链表就像是现实生活
中的铁链,因此这里要将铁链的第一环与后面的部分连接起来。这便是这一步的原理***/
//这里便说明了为什么链表添加新元素操作的时间复杂度为O(1)
}
return p;
}
//功能2:插入数据功能
link* insertElem(link* p, int elem, int add) {
link* temp = p;
//这一步实现的功能是防止在不恰当(不在链表大小范围内)的位置插入链表元素
for (int i = 1; i < add; i++) {
//遇到空地址时无效,add大于4以后为空地址
if (temp == NULL) {
cout << "插入位置无效" << endl;
return p;
}
temp = temp->next;//将temp的地址锁定到要插入链表元素的位置,这里便说明了为什么链表插入操作的时间复杂度为O(n)
}
//排除了上面的情况,就可以正常插入啦
link* c = (link*) new link;//老规矩,建立一个临时链表元素c
c->elem = elem;//插入新元素的数据
c->next = temp->next;//c.next=p.next 在链表元素c中储存下下一个链表元素的地址
temp->next = c;//p.next=c 把插入的链表元素前一位的储存地址的指针与插入元素的地址链接起来,这时铁链终于完整了
return p;
}
//功能3:删除数据功能(原理其实与插入大同小异啦,不多赘述)
link* delElem(link* p, int add) {
link* temp = p;
for (int i = 1; i < add; i++) {
temp = temp->next;//将temp的地址锁定到要插入链表元素的位置,这里便说明了为什么链表删除操作的时间复杂度为O(n)
}
link* del = temp->next;
temp->next = temp->next->next;
delete del;
return p;
}
//功能:查找数据功能(查找数据在链表中返回数据)
int selectElem(link* p, int elem) {
link* t = p;
int i = 1;
while (t->next) {
t = t->next;
if (t->elem == elem) {
return i;
}
i++;
}
return -1;
}
//功能:更改链表元素
link* amendElem(link* p, int add, int newElem) {
link* temp = p;
temp = temp->next;
for (int i = 1; i < add; i++) {
temp = temp->next;//通过逐层递增找到要更改位置的链表
}
temp->elem = newElem;
return p;
}
//遍历链表的所有元素并输出
void display(link* p) {
link* temp = p;
while (temp->next) {
temp = temp->next;
cout << temp->elem;
}
cout << endl;
}
int main() {
link* p = initLink();
display(p);
p = insertElem(p, 5, 4);
display(p);
p = delElem(p, 3);
display(p);
int address = selectElem(p, 2);
if (address == -1) {
cout << "没有该元素";
}
else {
cout << "元素 2 的位置为 " << address;
}
cout << "更改第 3 的位置的数据为 7:" << endl;
p = amendElem(p, 3, 7);
display(p);
return 0;
}
运行结果: