数据结构–链表
链表的定义
a)如果结构体成员变量中有指向同类节点的指针变量,那么就能够将一个个的结构具体的变串连起来,这样的一系列节点形象上像一条链子,我们称之为链表。
b)每个节点都是有2部分组成:数据区+地址区(指向自身结构体的指针变量)
c)其中指向自身类型节点的指针,我们称之为地址域。
d)最后一个节点没有下一个节点,地址域赋值为NULL。
链表是一个数据+指针的结构体集合,指针指向链表中下一数据结构体,按链表的结构,可分为单向链表,双向链表,循环链表,结构分别如下图所示:
链表特征
1、(单)链表:必须有链表头pHeader;
2、通过链表头,可以顺次向下访问所有节点。
3、如果是空链表链表头为0,pHeader=NULL;
4、链表尾节点:类似于null结尾的字符串,最后一个节点的指针pNext==0;
5、可以在任意位置插入和删除节点。
链表的操作
链表的操作包括:插入,删除,反转,修改和查找。
链表的声明
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "iostream"
#include "vector"
using namespace std;
typedef int DATA;
struct node{
DATA data;
node* P_next=0;
node(DATA _data){
data = _data;
}
};
class linkedlist{
int length=0;
public:
node *header, *tail;
void pushback(DATA _data); //尾插入数据
void insert_node(DATA _data, int position); //在某个位置插入数据
void delete_node(DATA _data); //删除数据
vector<node*> search_node(DATA _data); //查找数据
void modify_node(DATA _data1, DATA _data2); //修改数据
void roll_back(); //链表反转
void printlist(); //打印链表
linkedlist(){
};
~linkedlist(){
if (length>0){
node* temp_node;
while (header->P_next) {
temp_node = header->P_next;
delete header;
header = temp_node;
}
delete header;
}
cout<<"Deconstructed successfully!"<<endl;
}
};
注意:链表一般是建立在堆上的,所以一定要对链表进行析构,以回收新开辟的堆空间。
链表的插入
过程包括以下三步:
step1:找到要插入的位置以及该位置原来的元素以及指向该位置的指针;
step2:生成新的元素;
step3:将step1中的指针指向新的元素,该元素的指针对象指向step1中元素
void linkedlist::insert_node(DATA _data, int position){
if(position <= length){
int index = 0;
node* temp_node = header , *last_node = 0;
while (index<position) {
index ++;
temp_node = temp_node->P_next;
if(index == position -1)
{
last_node = temp_node;
if(temp_node->P_next) temp_node = temp_node->P_next;
else temp_node = 0;
break;
}
}
node* newnode = new node(_data);
if(temp_node){
newnode->P_next = temp_node;
}
else{
newnode->P_next = 0;
tail = newnode;
}
if(last_node) last_node->P_next = newnode;
else{
header = newnode;
}
length++;
}
else cout<<"position 超出索引"<<endl;
}
链表的尾插入
与链表的插入很相似,只是将新生成的结构数据指针设为0
void linkedlist::pushback(DATA _data){
if(length == 0){
header = new node(_data);
tail = header;
}
else{
node* newnode = new node(_data);
tail->P_next = newnode;
tail = newnode;
}
length ++;
}
链表的查找
采用从头到尾遍历的方法(感觉这种查找方法挺低效率的)。
vector<node*> linkedlist::search_node(DATA _data){
vector<node*> nodes;
if (length>0){
node* temp_node = header;
while(temp_node->P_next){
if(temp_node->data == _data){
nodes.push_back(temp_node);
}
else temp_node = temp_node->P_next;
}
if(temp_node->data == _data) nodes.push_back(temp_node);
}
return nodes;
}
链表的元素删除
链表的删除主要包括以下步骤:
step1:找到要删除的元素及位置以及指向该位置的指针;
step2: 将step1中的指针指向该元素下一个元素;
step3: 删除该元素。
void linkedlist::delete_node(DATA _data){
if(length >0){
node* temp_node = header, *last_node=header;
while (temp_node->P_next){
if(temp_node->data == _data){
last_node->P_next = temp_node->P_next;
delete temp_node;
temp_node = last_node;
length --;
}
last_node = temp_node;
temp_node = temp_node->P_next;
}
if(temp_node->data == _data) {
delete temp_node;
last_node->P_next = 0;
length --;
tail = last_node;
}
}
}
链表的反转
链表的反转,就是将链表原来的指向关系进行互逆,及原来元素A中的指针指向B,反转后变成B中的指针指向A,头尾交换。
void linkedlist::roll_back(){
if(length >1){
node* next_node, *last_node = header, *this_node=header->P_next;
last_node->P_next = nullptr;
tail = last_node;
while(this_node->P_next){
next_node = this_node->P_next;
this_node->P_next = last_node;
last_node = this_node;
this_node = next_node;
}
header=this_node;
header->P_next = last_node;
}
}