链表是线性表的链式存储方式,逻辑上相邻的数据在计算机内的存储位置不必相邻,逻辑上的相邻可以给每个元素附加一个指针域,指向下一个元素的存储位置;
链表的核心元素:
1,每个节点由数据域和指针域组成;
2,指针域指向下一个节点的内存地址;
3.在企业中应用于在linux内核中,有大量的数据结构需要用到双向链表,如:进程,文件,模块,页面等;
若采用双向链表的传统实现方式,需要为这些数据结构维护各自的链表,而且为每个链表都要设计插入删 除等操作函数,因为用来维持链表的next和prev指针指向对应类型的对象,因此一种数据结构的链表操作函数不能用于操作其他数据结构的链表;
单链表:
#include <iostream>
using namespace std;
//创建一个链表
typedef struct linknode {
int data;//数据域
linknode* next;//指针域
}linklist,linknode;//链表,节点
//初始化链表
bool initlinklist(linklist*& list) {
list = new linknode;
if (!list) {
return false;
}
list->next = NULL;
list->data = NULL;
return true;
}
//打印链表
void printlinklist(linklist*& list) {
linknode* p=NULL;
if (!list) {
cout << "链表为空!" << endl;
return;
}
p = list->next;
while (p) {
cout << p->data << ",";
p = p->next;
}
cout << endl;
}
//首插法
bool frontlinklist(linklist*& list, linknode* node) {
if(!list||!node){
return false;
}
node->next = list->next;
list->next = node;
true;
}
//尾插法
bool backlinklist(linklist*& list, linknode* node) {
if (!list || !node) {
return false;
}
linknode* last = NULL;
last = list;
while (last->next) {
last = last->next;
}
node->next = NULL;
last->next = node;
return true;
}
//任意位置插入元素
bool insertlinklist(linklist*& list, int seat, int& number) {
if (!list) {
return false;
}
//如果不定义临时变量,会使原来的链表数据错乱
linklist* s;
linklist* l;
l = list;
int i = 0;
while (l && i < seat - 1) {//查找位置seat-1的的节点,l指向该节点
l = l->next;
i++;
}
if (!l || i > seat - 1) {
return false;
}
s = new linklist;
s->data = number;
s->next = l->next;
l->next = s;//指向的是s的数据域
return true;
}
//查找元素
bool getelemlinklist(linklist*& list, int seat, int& number) {
if (!list || !list->next) {
return false;
}
linklist* p;
int index = 1;
p = list->next;
while (p && index < seat) {
p = p->next;
index++;
}
if (!p || index > seat) {
return false;
}
number = p->data;
return true;
}
//按值查找
bool fontelemlinklist(linklist* list, int number, int& seat) {
linklist* p;
p = list->next;
seat = 1;
if (!list || !list->next) {
seat = 0;
return false;
}
while (p && p->data != number) {
p = p->next;
seat++;
}
if (!p) {
seat = 0;
return false;
}
return true;
}
//删除元素
bool deleteelemlinklist(linklist* list, int seat) {
if (!list || !list->next) {
return false;
}
linklist* p, * q;
int index = 0;
p = list;
while ((p->next) && (index < seat - 1)) {
p = p->next;
index++;
}
if (!p->next || index > seat - 1) {
return false;
}
q = p->next;//临时保存被删除的节点的地址以备释放空间
p->next = q->next;//改变删除节点前区节点的指针域
delete[]q;//释放被删除节点的空间
return true;
}
//销毁链表
bool deletelinklist(linklist*& list) {
if (!list) {
cout << "没有" << list << "链表,删除失败!" << endl;
return false;
}
linklist* p=list;
while (p) {
list = list->next;//指向下一个节点
cout << "删除元素:" << p->data << endl;
delete[]p;//删除当前节点
p = list;
}
return true;
}
循环链表
循环链表的操作和单链表的操作基本上没有多大的区别,就是在初始化和尾部插入元素的时候有所不同
#include <iostream>
using namespace std;
typedef struct listnode{
int data;
listnode* next;
}cyclinklist,listnode;
//初始化循环链表
bool init_list(cyclinklist*& list) {
list = new listnode;//初始化是生成一个节点
//判断申请内存是否成功
if (!list) {
return false;
}
//节点指向自己,因为初始化时只有一个节点
list->next = list;
list->data = -1;
return true;
}
//打印链表
void print_list(cyclinklist* list) {
cyclinklist* p;
p = list->next;
while (p != list) {
cout << p->data << ",";
p = p->next;
}
cout << endl;
}
//尾插法
bool back_list(cyclinklist*& list, listnode* node) {
//定义一个临时节点
listnode* last = NULL;
if (!list || !node) {
return false;
}
//把临时节点的指向整个链表
last = list;
//临时节点不等于链表首节点时,就一直往后执行
while (last->next != list) {
last = last->next;
}
//新节点插入在后面,首节点指向新节点
node->next = list;
last->next = node;
return true;
}
双向链表
在单链表的基础上给每个元素附加两个指针域,一个存储前一个元素的地址,一个存储下一个元素的地址,这样就形成了一个双向链表
#include <iostream>
using namespace std;
//创建一个双向链表
typedef struct linklist {
int data;//节点的数据域
struct linklist* next;//下一个节点
struct linklist* prev;//上一个节点
}linknode,linklist;//linklist为指向结构体linknode的指针类型
//初始化双向链表
bool init_DB_linklist(linklist*& list) {
list = new linknode;//生成新节点为头节点,用头指针list指向头节点
//判断节点生成是否成功
if (!list) {
return false;
}
list->next = NULL;//头节点的next指针域设置为空
list->prev = NULL;//头节点的指针域设置为空
list->data = -1; //数据域先设置为-1
return true;
}
//打印双向链表
void print_DB_linklist(linklist* list) {
if (!list) {
return;
}
linknode* p = NULL;
p = list;
while (p->next) {
cout << p->next->data << ",";
p = p->next;
}
cout << endl;
//逆向打印
while (p->prev) {
cout << p->data << ",";
p = p->prev;
}
cout << endl;
}
//双向链表添加元素: 前插法
bool front_insert_DB_linklist(linklist*& list, linknode* node) {
if (!list || !node) {
return false;
}
//只有头节点
if (list->next == NULL) {
node->next = NULL;
node->prev = list;//新节点prev指针指向头节点
list->next = node;//头节点next指针指向新节点
}
else {
list->next->prev = node;//第二个节点的prev指向新节点
node->next = list->next;//新节点next指针指向第二个节点
node->prev = list; //新节点prev指针指向头节点
list->next = node; //头节点next指针指向新节点,完成插入
}
return true;
}
//双向链表添加元素: 尾插法
bool back_DB_linklist(linklist*& list, linknode* node) {
if (!list || !node) {
return false;
}
linknode* last = NULL;
last = list;
while (last->next) {
last = last->next;
}
node->next = NULL;
last->next = node;
node->prev = last;
return true;
}
//双向链表添加元素: 任意位置插入
bool insert_DB_linklist(linklist*& list, int seat, int& val) {
if (!list || !list->next) {
return false;
}
linklist* p;
linklist* s;
int i;
p = list;
i = 0;
while (p && i < seat) {//查找位置i的节点,p指向该节点
p = p->next;
i++;
}
if (!p || i > seat) {
cout << "不存在节点:" << seat << endl;
return false;
}
s = new linknode;//生成新节点
s->data = val;
s->next = p;
s->prev = p->prev;
p->prev->next = s;
p->prev = s;
return true;
}
//双向链表获取元素
bool getelem_DB_linklist(linklist*& list, int seat, int& val) {
//在带头节点的双向链表list中查找第seat个元素
//用val记录第seat个数据元素的值
int index;
linklist* p;
if (!list || !list->next) {
return false;
}
p = list->next;
index = 1;
while (p && index < seat) {//顺着链表往后扫描,直到p指向第seat个元素或p为空
p = p->next;//p指向下一个节点
index++; //计数器index相应加1
}
if (!p || index > seat) {
return false;
}
val = p->data;
return true;
}
//双向链表删除元素
bool delete_DB_linklist(linklist*& list, int seat) {
if (!list || !list->next) {
cout << "双向链表为空" << endl;
return false;
}
linklist* p;
int index;
//不可以删除头节点
if (seat < 1) {
return false;
}
p = list;
index = 0;
while (p && index < seat) {
p = p->next;
index++;
}
//当节点不存在时,返回失败
if (!p) {
return false;
}
p->prev->next = p->next;//改变删除节点前节点的next指针域
if (p->next) {
p->next->prev = p->prev;//改变删除节点后节点的prev指针域
}
delete[] p;//释放被删除节点的空间
return true;
}
//销毁双向链表
void dest_DB_linklist(linklist*& list) {
//定义临时节点p指向头节点
linklist* p = list;
cout << "销毁链表" << endl;
while (p) {
list = list->next;//list指向下一个节点
cout << "删除" << p->data << endl;
delete[] p;
p = list;
}
}
C++面向对象方式实现
#pragma once
#include<iostream>
using namespace std;
//定义一个节点的类,使用泛型编程可以兼容更多的数据类型
template<typename T>
class node {
public:
node<T>* next;//指向下一个节点的指针
node<T>* prev;//指向上一个节点的指针
T data;//节点中保存的数据
};
#include "node.h"
//链表的类
template<typename T>
class list
{
public:
list();//链表的默认构造函数
list(const list& cp);//拷贝构造函数
~list();//析构函数
void add_List(T elem);//给链表添加数据
void remove_List(T index);//移除链表中的某个节点
T find(int index);//查找链表中的某个节点
bool isEmpty();//判断链表是否为空
int size_List();//链表的长度
void pint_List();//打印链表
void res_pint_List();//反向打印链表
void removeAll();//删除链表中所有的节点
private:
node<T>* m_head;//链表的头节点
node<T>* m_tail;//链表的尾节点
int m_length;//链表的长度
};
//默认构造函数
template<typename T>
list<T>::list()
{
//先给头和尾节点分配内存空间
m_head = new node<T>;
m_tail = new node<T>;
//头节点的下一个位置的尾节点,上一个位置为空;
m_head->next = m_tail;
m_head->prev = NULL;
//尾节点的下一个位置为空,上一个位置是头节点
m_tail->next = NULL;
m_tail->prev = m_head;
//长度初始化为0;
m_length = 0;
}
//拷贝构造函数
template<typename T>
list<T>::list(const list& cp)
{
m_head = new node<T>;
m_head->prev = NULL;
m_tail = new node<T>;
m_tail->prev = m_head;
m_length = 0;
node<T>* tmp = cp.m_head;
while (tmp->next != cp.m_tail)
{
tmp = tmp->next;
m_tail->data = tmp->data;
node<T>* p = new node<T>;
p->prev = m_tail;
m_tail->next = p;
m_tail = p;
m_length++;
}
m_tail->next = NULL;
}
template<typename T>
list<T>::~list()
{
while (m_length != 0)
{
node<T>* p = m_head->next;
delete p;
m_head = p;
m_head->prev = NULL;
}
}
template<typename T>
void list<T>::add_List(T elem)
{
node<T>* tmp = m_tail;
m_tail->data = elem;
m_tail->next = new node<T>;
node<T>* p = m_tail;
m_tail = m_tail->next;
m_tail->prev = p;
m_tail->next = NULL;
m_length++;
}
//删除节点
template<typename T>
void list<T>::remove_List(T index)
{
if (m_length == 0)
{
cout << "链表为空!" << endl;
return;
}
node<T>* p = m_head;
while (p->next != NULL)
{
p = p->next;
if (p->data == index)
{
node<T>* tmp = p->prev;
tmp->next = p->next;
p->next->prev = tmp;
delete p;
m_length--;
return;
}
}
}
//查找节点
template<typename T>
T list<T>::find(int index)
{
if (m_length == 0)
{
cout << "链表为空!" << endl;
return NULL;
}
if (index >= m_length)
{
cout << "输入的节点位置有误!" << endl;
return NULL;
}
int x = 0;
T data;
node<T>* p;
if (index <= m_length)
{
p = m_head->next;
while (p->next != NULL && x++ != index)
{
p = p->next;
}
}
else {
p = m_tail->prev;
while (p->prev != NULL && x++ != index)
{
p = p->prev;
}
}
return p->data;
}
template<typename T>
bool list<T>::isEmpty()
{
if (m_length == 0)
{
return true;
}
return false;
}
template<typename T>
int list<T>::size_List()
{
return m_length;
}
template<typename T>
void list<T>::pint_List()
{
if (m_length == 0)
{
return;
}
node<T>* p = m_head->next;
while (p != m_tail)
{
cout << p->data << ",";
p = p->next;
}
cout << endl;
}
template<typename T>
void list<T>::res_pint_List()
{
if (m_length == 0)
{
return;
}
node<T>* p = m_tail->prev;
while (p->prev != m_head)
{
cout << p->data << ",";
p = p->prev;
}
cout << endl;
}
template<typename T>
void list<T>::removeAll()
{
if (m_length == 0)
{
return;
}
node<T>* p = m_head->next;
while (p != m_tail)
{
node<T>* tmp = p;
p = p->next;
delete tmp;
}
m_head->next = m_tail;
m_tail->prev = m_head;
m_length = 0;
}
int main(void)
{
list<int>list1;
for (int i = 0; i < 5; i++) {
list1.add_List(i);
}
list1.pint_List();
cout << list1.size_List() << endl;
cout << list1.find(1) << endl;
list1.remove_List(1);
list1.removeAll();
list1.res_pint_List();
system("pause");
}
运行结果: