1、链表的概念
链表:数据元素随机存储在内存中,通过指针维系数据之间“一对一”的逻辑关系,这样的存储结构就是链表。
注意:一个结点只有一个后继,可以有多个前驱。
2、虚拟结点
(1)虚拟结点就是一个结点dummyNode,其next指针指向head,也就是dummyNode->next = head。或者从方法(函数)里返回的时候,则应使用dummyNode.next。
(2)虚拟结点是为了方便处理首部结点,否则我们需要在代码里单独处理首部结点的问题。在链表反转里,该方式能大大降低解题难度。
3、结点的定义
struct ListNode{
int val;
struct ListNode* next;
};
4、创建链表
举例:创建0~4这样一个链表
#include<bits/stdc++.h>
using namespace std;
//定义结点
struct ListNode{
int val;
struct ListNode* next;
};//有个分号
//创建链表
struct ListNode* initLink(){
int i;
//1、创建头指针
struct ListNode* p = NULL;
//2、创建头结点
struct ListNode* temp = (struct ListNode*)malloc(sizeof(struct ListNode));
temp->val = 0;
temp->next = NULL;
//头指针指向头结点
p=temp;
for(i=1;i<5;i++){
//创建一个结点
struct ListNode* a = (struct ListNode*)malloc(sizeof(struct ListNode));
a->val = i;
a->next = NULL;
temp->next = a;
temp = temp->next;
}
return p;
}
int main(){
struct ListNode* p = NULL;
printf("初始化链表为:\n");
p = initLink();
system("pause");
return 0;
}
5、遍历链表(打印链表)
要新建指针来遍历链表
#include<bits/stdc++.h>
using namespace std;
//定义结点
struct ListNode{
int val;
struct ListNode* next;
};//有个分号
//创建链表
struct ListNode* initLink(){
int i;
//1、创建头指针
struct ListNode* p = NULL;
//2、创建头结点
struct ListNode* temp = (struct ListNode*)malloc(sizeof(struct ListNode));
temp->val = 0;
temp->next = NULL;
//头指针指向头结点
p=temp;
for(i=1;i<5;i++){
//创建一个结点
struct ListNode* a = (struct ListNode*)malloc(sizeof(struct ListNode));
a->val = i;
a->next = NULL;
temp->next = a;
temp = temp->next;
}
return p;
}
//打印链表
void printList(struct ListNode* p){
//temp指针用来遍历链表
struct ListNode* temp = p;
while(temp){
printf("%d ",temp->val);
temp = temp->next;
}
printf("\n");
}
//获取链表的长度
int32_t getLength(struct ListNode* p){
struct ListNode* temp = p;
int length = 0;
while(temp){
length ++;
temp = temp->next;
}
return length;
}
int main(){
struct ListNode* p = NULL;
printf("initlist:\n");
//创建链表{0,1,2,3,4}
p = initLink();
//打印链表{0,1,2,3,4}
printList(p);
int length = getLength(p);
printf("list length:\n%d\n",length);
system("pause");
return 0;
}
6、链表插入
(1)链表插入要考虑3种情况:首部、中部、尾部
(2)在首部插入时要将head重新指向表头。创建一个新结点newNode,执行newNode->next = head,再执行head = newNode就行了。
(3)在中部插入和在尾部插入代码一样。需要在插入位置的前一个结点停下,先执行new->next = 前一个结点->next,再执行前一个结点->next = new。
(4)3中的顺序不能错,因为如果先执行前一个结点->next = new,再执行new->next = 前一个结点->next,第二句代码意思就是结点本身指向结点本身。
#include<bits/stdc++.h>
using namespace std;
//定义结点
struct ListNode{
int val;
struct ListNode* next;
};//有个分号
/*创建链表
struct ListNode* initLink(){
int i;
//1、创建头指针
struct ListNode* p = NULL;
//2、创建头结点
struct ListNode* temp = (struct ListNode*)malloc(sizeof(struct ListNode));
temp->val = 0;
temp->next = NULL;
//头指针指向头结点
p=temp;
for(i=1;i<5;i++){
//创建一个结点
struct ListNode* a = (struct ListNode*)malloc(sizeof(struct ListNode));
a->val = i;
a->next = NULL;
temp->next = a;
temp = temp->next;
}
return p;
}
*/
//打印链表
void printList(struct ListNode* p){
//temp指针用来遍历链表
struct ListNode* temp = p;
while(temp){
printf("%d ",temp->val);
temp = temp->next;
}
printf("\n");
}
//获取链表的长度
int32_t getLength(struct ListNode* p){
struct ListNode* temp = p;
int length = 0;
while(temp){
length ++;
temp = temp->next;
}
return length;
}
struct ListNode* insterNode(struct ListNode* head,struct ListNode* nodeInster,int position){
//链表本身是空的,直接返回插入的结点
if(head == NULL){
return nodeInster;
}
int size = getLength(head);
if(position > size+1 || position < 1){
printf("位置参数越界\n");
return head;
}
//在链表头部插入
if(position == 1){
nodeInster->next = head;
head = nodeInster;
return head;
}
//在中间位置插入和在末尾插入代码一样
struct ListNode* pNode = head;
int count = 1;
while(count < position - 1){
pNode = pNode->next;
count ++;
}
nodeInster->next = pNode->next;
pNode->next = nodeInster;
return head;
}
//测试一下
void textInster(){
struct ListNode* head = NULL;
struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));
node->val = 1;
node->next = NULL;
//插入第一个元素
head = insterNode(head,node,1);
printList(head);
//在末尾插入元素
node = (struct ListNode*)malloc(sizeof(struct ListNode));
node->val = 3;
head = insterNode(head,node,2);
printList(head);
//在中间插入元素
node = (struct ListNode*)malloc(sizeof(struct ListNode));
node->val = 2;
head = insterNode(head,node,2);
printList(head);
}
int main(){
/*struct ListNode* p = NULL;
printf("initlist:\n");
//创建链表{0,1,2,3,4}
p = initLink();
//打印链表{0,1,2,3,4}
printList(p);
int length = getLength(p);
printf("list length:\n%d\n",length);*/
textInster();
system("pause");
return 0;
}
7、链表删除
(1)链表删除要考虑3种情况:删除表头结点、删除中间结点、删除尾结点
(2)删除中间结点和删除尾结点代码一样。
(3)删除中间结点时,代码不能这么写(虽然字面上是这么个意思)
cur->next = cur->next->next;
free(cur->next); //这么写会出现。。。所以要新建一个结点。
struct ListNode* tmp = cur->next;
cur->next = tmp->next;
free(tmp);
#include<bits/stdc++.h>
using namespace std;
//定义结点
struct ListNode{
int val;
struct ListNode* next;
};//有个分号
//创建链表
struct ListNode* initLink(){
int i;
//1、创建头指针
struct ListNode* p = NULL;
//2、创建头结点
struct ListNode* temp = (struct ListNode*)malloc(sizeof(struct ListNode));
temp->val = 0;
temp->next = NULL;
//头指针指向头结点
p=temp;
for(i=1;i<10;i++){
//创建一个结点
struct ListNode* a = (struct ListNode*)malloc(sizeof(struct ListNode));
a->val = i;
a->next = NULL;
temp->next = a;
temp = temp->next;
}
return p;
}
//打印链表
void printList(struct ListNode* p){
//temp指针用来遍历链表
struct ListNode* temp = p;
while(temp){
printf("%d ",temp->val);
temp = temp->next;
}
printf("\n");
}
//获取链表的长度
int32_t getLength(struct ListNode* p){
struct ListNode* temp = p;
int length = 0;
while(temp){
length ++;
temp = temp->next;
}
return length;
}
//删除某个结点
struct ListNode* deleteNode(struct ListNode* head,int position){
if(head == NULL){
return NULL;
}
int size = getLength(head);
if(position > size || position < 1){
printf("输入的位置参数有误\n");
return head;
}
if(position == 1){
struct ListNode* curNode = head;
head = head->next;
free(curNode);
return head;
}
else{
struct ListNode* cur = head;
int count = 1;
while(count < position - 1){
cur = cur->next;
count ++;
}
/*cur->next = cur->next->next;
free(cur->next); 不能这样写,会出现。。。要新建一个结点*/
struct ListNode* tmp = cur->next;
cur->next = tmp->next;
free(tmp);
return head;
}
}
//测试一下
void textDelete(){
struct ListNode* p = NULL;
printf("create list:\t");//\t的意思是补全前面字符串的位数到8的整数倍
//创建链表0~9
p = initLink();
printList(p);
//删除头节点
p = deleteNode(p,1);
printList(p);
//删除中间结点
p = deleteNode(p,2);
printList(p);
//删除尾结点
int length = getLength(p);
p = deleteNode(p,length);
printList(p);
}
int main(){
/*struct ListNode* p = NULL;
printf("initlist:\n");
//创建链表{0,1,2,3,4}
p = initLink();
//打印链表{0,1,2,3,4}
printList(p);
int length = getLength(p);
printf("list length:\n%d\n",length);*/
textDelete();
system("pause");
return 0;
}