1、链式存储的基本实现
该部分主要通过leetcode编程练习整理,接下来结合代码注释来分别解释单链表和双链表(注意到编程网站中并没有按值查找。实际上也可以在leetcode结合复习即可)。可结合具体网址练习。网址如下:链表 - LeetBook
单链表
单链表的具体结构、概念和操作如下:
1、构建单链表数据结构
class MyLinkedList {
/*
1、class默认属性为私有(struct里属性为公有)
2、MyLinkedList里封装结点所具备的属性,并在私有属性上设置一个head结点和链表长度size。
*/
public:
struct node {
int val;
node* next;
//初始化一个节点,其数值为x,指针为空
node(int x) : val(x), next(NULL) {}
};
//...
//...具体方法省略...
//...
private:
int size;
node* head;
};
2、具体方法
初始化
MyLinkedList() {
head = new node(0);//初始化一个头结点,通过new将其放入
size = 0;
}
在C++中,我们使用new关键字手动(由程序员手动)创建一个内存块在堆区(堆区的具体delete最终是由操作系统自动回收),设置的头结点没有size。
按位查找
int get(int index) {//index是根据计算机计数输入
if (index<0 || index>size-1) {
return -1;//获取失败
}
node* cur = (head->next);//设立一个辅助指针,指向最开始的head节点或者head->next都可
for (int i = 0; i < index; i++) {
//循环一次移动一次
cur = cur->next;
}
return cur->val;
}
首部添加节点
void addAtHead(int val) {
//头结点只需要新建一个待插入结点即可
node* temp = new node(val);
temp->next = head->next;
head->next = temp;
size += 1;
}
这部分很简单,并不需要辅助指针因为可以直接使用head。
尾部添加节点
void addAtTail(int val) {
//头结点采用头插法,所以与插入首部的区别在于先遍历到后面最后一个结点
node* cur = head;
/*
* 2->5->7->(8),应该让cur指到8
*/
while (cur->next) {
cur = cur->next;
}
node* temp = new node(val);
temp->next = cur->next;
cur->next = temp;
size += 1;
}
插入节点
void addAtIndex(int index, int val) {
if (index == 0) addAtHead(val);
else if (index == size) addAtTail(val);
else if (index > 0 && index < size) {
node* cur = head;
for (int i = 0; i < index; i++) {
//循环一次移动一次
cur = cur->next;
}
node* temp = new node(val);
//关键
temp->next = cur->next;
cur->next = temp;
//关键
size += 1;
}
else {
return;
}
}
在两个关键注释中就是插入节点的关键代码。其时间复杂度花费于查找上,所以插入总时间复杂度为O(n)。其插入过程本身为O(1)。
删除节点
void deleteAtIndex(int index) {
if (index < 0 || index >= size) return;
node* cur = head;
for (int i = 0; i < index; i++) {
//循环一次移动一次
cur = cur->next;
}
cur->next = cur->next->next;
size -= 1;
}
双链表
双链表的基本结构、概念和操作如下:
1、构建双链表数据结构
class MyLinkedList {
//跟单链表一样,在里面设置结构体node。
struct node {
int val;
node* next, * prior;
node(int x) : val(x), next(NULL), prior(NULL) {}
};
//...
//...
private:
node* head;
int size;
};
2、具体方法
初始化
public:
MyLinkedList() {
head = new node(0);
size = 0;
}
该部分跟单链表类似。
按位查找
int get(int index) {
if (index < 0 || index >= size) return -1;
node* cur = head->next;
while (index--) {
cur = cur->next;
}
return cur->val;
}
该部分跟单链表类似。
首部添加节点
void addAtHead(int val) {
//创建一个结点
node* temp = new node(val);
/*
插入时应该是先处理后面再处理前面
*/
if (head->next)
//如果头结点后面有结点,需要将该结点的prior指针指向temp
head->next->prior = temp;
temp->next = head->next;
temp->prior = head;
head->next = temp;
size++;
}
在注释中提到,这里处理添加节点首先要判断head->next是否有节点。
尾部添加节点
void addAtTail(int val) {
node* cur = head;
while (cur->next) {
cur = cur->next;
}
//此处代码跟addAtHead一致
node* temp = new node(val);
cur->next = temp;
temp->prior = cur;
temp->next = NULL;
size++;
}
同样的,其cur指向最后一个元素,在最后面添加元素时注意temp的prior和next指向赋值。
插入节点
void addAtIndex(int index, int val) {
if (index == 0) addAtHead(val);
else if (index == size) addAtTail(val);
else if (index > 0 && index < size) {
node* cur = head->next;
while (index--) {
cur = cur->next;
}
//指针指到temp所插入的后一个节点
node* temp = new node(val);
temp->next = cur;
temp->prior = cur->prior;
cur->prior->next = temp;
cur->prior = temp;
size++;
}
else {
return;
}
}
删除节点
void deleteAtIndex(int index) {
if (index < 0 || index >= size) return;
node* cur = head->next;
while (index--) {
cur = cur->next;
}
if (cur->next) {
//删除节点不是最后一个元素
cur->next->prior = cur->prior;
cur->prior->next = cur->next;
}
else {
cur->prior->next = NULL;
}
size--;
}
这里处理时跟前面的首部添加节点类似,都需要判断该index所处的节点是否为最后一个节点。