c++实现单链表
1、链表的特点(链表是在空间中new出来的一段空间)(注意链表和数组意义具有零号数据位,即头节点的下一位)
-
链表是一种常见的数据结构,进行删除和插入操作十分简单,但是相对于其他的连续空间来说,遍历速度比较慢。
-
链表的结构:头节点head没有记录数量,定义时候一般定义为空。

它由很多的结点node组成list。
-
链表的删除和插入都要建立在有数据的情况下,比如链表里面存储了10个信息,你要在第13个空间插入数据和删除数据,那都是不现实的。
2、链表的实现
因此就像前面的电话本的构成一样,node相当于person类,很多的person类组成了电话本这个类(list)。
-
节点node的定义:包含指针域和数据域
class node { public: int data;//数据域 node* next;//指针域 };
-
list的类的实现:指向第一个node和一个记录链表内数据的整型:
//定义一个链表
class list
{
public:
node* head;//这里为什么要用指针呢?因为我的节点node是new出来的,需要一个地址类型的数据记录
int size;//链表本身没有长度,这里只是记录以下链表内数据的个数,用于打印链表用的
};
-
list的初始化(将前面定义好的node和list相联系):
这里一定要注意list内部的第一个节点head的建立,一定要new出来,因为是用来定位用的,后面打印的时候也不打印头节点
//定义好list和node怎么将它们联系起来呢:初始化(返回一个list类型的指针)
list* list_init() { list* L = new list;//定义一个链表 L->size = 0;//链表内的数据记录个数为零 L->head = new node;//创建第一个头节点,一定要给new出来 L->head->data = NULL;//头节点的数据和指针都置空 L->head->next = NULL; return L; }
-
list的指定某个指定位置的数据添加(注意如果是空的链表,那么一定要从第一个开始添加)
//创建好一个链表之后我们进行数据的插入
void list_insert(list* L,int pos,int data)//这里为什么要用指针呢?因为初始化的L就是一个地址 { if (L == NULL)//如果数据为空那么从表头插入 { pos = 0; } node* new_node = new node;//我们的目的是将数据data包装成节点,再插入 new_node->data = data; new_node->next = NULL;//我们暂时先把这个节点的指针域指空,后期要用时候再重新指向 node* pos_node = L->head;//从0号head节点开始遍历 for (int i = 0; i < pos; i++) { pos_node = pos_node->next; } //到这里的话出来的pos_node节点就是原来list中第pos位的前一个节点 new_node->next = pos_node->next;//将new_node的指针指向定位到的节点的指针指向的地方 pos_node->next = new_node;//将定位到的节点的指针指向new_node L->size++; }
-
list的删除某个指定的节点
//删除指定位置的节点
void remove_pos_node(list* L, int pos)
{
if (L == NULL)//链表为空的话无法删除
{
return;
}
node* pos_node = L->head;
for (int i = 0; i < pos; i++)
{
pos_node = pos_node->next;
}//这里出来的pos_node是应该删除位置的前一个节点
pos_node->next = pos_node->next->next;//删除该节点
L->size--;
}
-
list修改某个指定位置的数据
//修改指定位置的数据
void modified_pos_node(list* L,int pos,int data)
{
if (L == NULL)
{
cout << "链表为空" << endl;
}
node* modinode = L->head;
for (int i = 0; i < pos; i++)
{
modinode = modinode->next;
} //这里出来的modinode就是想要修改的节点的前一个节点
modinode->next->data = data;
}
-
list打印指定的链表
void printf_list(list *L)
{
if (L->size==0)
{
cout << "链表无数据" << endl;
}
node* pcurrent = L->head->next;//跳过头节点的打印,因为头节点不放数据,只用来定位
for (int i = 0; i < L->size; i++)
{
cout<< pcurrent->data << "\t";
pcurrent = pcurrent->next;
}
cout << endl;
}
-
主函数的实现:
void test1()
{
list* L = list_init();
for (int i = 0; i < 10; i++)
{
list_insert(L,i,i);
}
list_insert(L,5,4);
cout << "插入0-9的链表为:" << endl;
printf_list(L);
remove_pos_node(L,5);
cout << "删除第5号node后的地址为:" << endl;
printf_list(L);
}
-
以上的所有综合在一起链表的操作:
#include<iostream> using namespace std; //定义一个节点 class node { public: int data;//数据域 node* next;//指针域 }; //定义一个链表 class list { public: node* head; int size;//链表本身没有长度,这里只是记录以下链表内数据的个数,用于打印链表用的 }; //定义好list和node怎么将它们联系起来呢:初始化(返回一个list类型的指针) list* list_init() { list* L = new list; L->size = 0; L->head = new node; L->head->data = NULL; L->head->next = NULL; return L; } //创建好一个链表之后我们进行数据的插入 void list_insert(list* L,int pos,int data) { if (L == NULL)//如果数据为空那么从表头插入 { pos = 0; } node* new_node = new node;//我们的目的是将数据data包装成节点,再插入 new_node->data = data; new_node->next = NULL;//我们暂时先把这个节点的指针域 node* pos_node = L->head;//从0号head节点开始遍历 for (int i = 0; i < pos; i++) { pos_node = pos_node->next; } //到这里的话出来的pos_node节点就是原来list中第pos位的前一个节点 new_node->next = pos_node->next;//将new_node的指针指向定位到的节点的指针指向的地方 pos_node->next = new_node;//将定位到的节点的指针指向new_node L->size++; } //删除指定位置的节点 void remove_pos_node(list* L, int pos) { if (L == NULL)//链表为空的话无法删除 { return; } node* pos_node = L->head; for (int i = 0; i < pos; i++) { pos_node = pos_node->next; }//这里出来的pos_node是应该删除位置的节点 pos_node->next = pos_node->next->next;//删除该节点 L->size--; } //修改指定位置的数据 void modified_pos_node(list* L,int pos,int data) { if (L == NULL) { cout << "链表为空" << endl; return; } node* modinode = L->head; for (int i = 0; i < pos; i++) { modinode = modinode->next; }//这里出来的modinode就是想要修改的节点的前一个节点 modinode->next->data = data; } //打印指定的列表 void printf_list(list *L) { if (L->size==0) { cout << "链表无数据" << endl; return; } node* pcurrent = L->head->next; for (int i = 0; i < L->size; i++) { cout<< pcurrent->data << "\t"; pcurrent = pcurrent->next; } cout << endl; } void test1() { list* L = list_init(); for (int i = 0; i < 10; i++) { list_insert(L,i,i); } cout << "插入0-9的链表为:" << endl; printf_list(L); modified_pos_node(L,7,12);//修改第7个位置上的数据为12 cout << "修改第7号node后的数据为:" << endl; printf_list(L); remove_pos_node(L,5); cout << "删除第5号node后的地址为:" << endl; printf_list(L); } int main() { test1(); system("pause"); return 0; }
3、看完力扣上的链表之后更为聪明的方法:
#include<iostream>
using namespace std;
//在类里写的话可以不用考虑每次调用一个方法的时候需要重新传入一个链表
class MyLinkedList
{
private:
//定义一个链表节点
struct listnode
{
int val;
listnode* next;
listnode(int data)
{
this->val = data;
this->next = NULL;
}
};
//定义一个链表
listnode* head;
int size;
//我们最终是要用mylist去定义链表,所以要有初始化的值
public:
MyLinkedList()
{
this->head = new listnode(0);
this->size = 0;
}
//获取链表中第 index 个节点的值。如果索引无效,则返回-1。
int get(int index)
{
if (index >= this->size || index < 0)
{
return -1;
}
listnode* indexnode = this->head;
for (int i = 0; i <= index; i++)//这里是到index个节点的位置,这个index包括0,是从0开始计数的
{
indexnode = indexnode->next;
}
return indexnode->val;
}
//addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
void addAtHead(int val)
{
listnode* newnode = new listnode(val);
newnode->next = this->head->next;
this->head->next = newnode;
this->size++;
}
//addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
void addAtTail(int val)
{
listnode* newnode = new listnode(val);
listnode* pos_node = this->head;
for (int i = 0; i < this->size; i++)
{
pos_node = pos_node->next;
}
pos_node->next = newnode;
this->size++;
}
//addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,
//则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
void addAtIndex(int index,int val)
{
if (index < 0)
{
addAtHead(val);
}
else if (index == this->size)
{
addAtTail(val);
}
else if(index > this->size)
{
return;
}
else
{
listnode* newnode = new listnode(val);
listnode* pos_node = this->head;
for (int i = 0; i < index; i++)
{
pos_node = pos_node->next;
}
newnode->next = pos_node->next;
pos_node->next = newnode;
this->size++;
}
}
//deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
void deleteAtIndex(int index)
{
if (index < 0 || index >= this->size)
{
cout << "索引无效" << endl;
return;
}
listnode* pos_node = this->head;
for (int i = 0; i < index; i++)
{
pos_node = pos_node->next;
}
pos_node->next = pos_node->next->next;
this->size--;
}
//打印这个链表
void list_print()
{
listnode* pos_node = this->head;
for (int i = 0; i < this->size; i++)
{
pos_node = pos_node->next;
cout << pos_node->val << " ";
}
cout << endl;
}
~MyLinkedList()
{
if (this->head != NULL)
{
delete this->head;
this->head = NULL;
}
}
};
int main()
{
MyLinkedList* linkedList = new MyLinkedList;
linkedList->addAtHead(1);
linkedList->addAtTail(3);
linkedList->addAtIndex(1, 2); //链表变为1-> 2-> 3
linkedList->get(1); //返回2
linkedList->deleteAtIndex(1); //现在链表是1-> 3
linkedList->get(1);
linkedList->list_print();
system("pause");
return 0;
}

浙公网安备 33010602011771号