什么是链表
链表属于线性表的一种,所有的数据按线性顺序排列。还有一种线性表是数组,这种数据结构各有各的优点,数组可以随机访问,并且可以根据下标在O(1)的时间内访问数据,而链表不可以随机访问,链表的顺序是由各个对象里的指针决定的。数组在内存中是顺序存储,所以会占一大部分连续的存储空间,而链表可以分散存储,之间的联系靠指针指向就可以,方便使用内存的零碎的空间。在增删方面,数组也是不理想的,每次增删都要移动数据,最坏的情况下是O(n-1),而链表则可以修改指针的指向在O(1)的时间内就可以完成增删,非常方便。
链表的节点一般包括数据域和指针域
头节点的数据域一般存放链表的整体信息,比如链表的长度信息。
需求
编写链表数据结构,要包括基本的增删改查,此次我用c++实现,既接近底层,又可以用类的思想,更好理解面向对象编程。
代码实现
首先新建一个头文件,用于声明要用到结构体的定义和类Linklist的定义。head.h
#include <iostream>
using namespace std;
struct Node {
int value;
Node* next;
Node(int num) :value(num),next(NULL) {};
Node() {};
};
class LinkList {
public:
void create(); //初始化
void insertHead(Node*); //头插法
void insertTail(Node*); //尾插法
Node* findByIndex(int); //根据索引查找节点,并返回节点的指针,注意0返回头节点
Node* findByValue(int); //根据值查找节点,并返回节点的指针,注意0返回头节点
int getLength(); //获取链表的长度
void deleteByIndex(int); //根据索引删除节点
void deleteByValueOnce(int); //根据节点值删除第一个节点
void deleteByValueAll(int);//根据节点值删除所有节点
void editByIndex(int,int); //根据索引修改节点的值
void print();
private:
Node* head; //头节点指针,value用于存放链表的长度
};
LinkList实现的cpp文件
#include "head.h"
void LinkList::create() {
head = new Node();
head->next = NULL;
head->value = 0;
}
void LinkList::insertHead(Node* p) {
p->next = head->next;
head->next = p;
head->value++;
}
void LinkList::insertTail(Node* p) {
Node* tail = findByIndex(head->value);
if (tail == NULL)
insertHead(p);
else {
p->next = tail->next;
tail->next = p;
}
head->value++;
}
Node* LinkList::findByIndex(int index){
Node* p = head;
int i = 0;
if (index<0||index >getLength()) {
cout << "索引非法!" << endl;
return NULL;
}
while (p) {
if (i == index)
return p;
else {
p = p->next;
i++;
}
}
return NULL;
}
Node* LinkList::findByValue(int value) {
Node* p = head->next;
for (;p;p=p->next){
if (p->value == value)
return p;
}
return NULL;
}
int LinkList::getLength() {
return head->value;
}
void LinkList::deleteByIndex(int index) {
if (index == 0) {
cout << "不能删除头节点!" << endl;
return;
}
Node* p = findByIndex(index);
if (!p) {
cout << "删除失败!" << endl;
return;
}
else {
Node* q = findByIndex(index - 1);
q->next = p->next;
head->value--;
delete p;
}
}
void LinkList::deleteByValueOnce(int value) {
Node* p = head->next;
Node* q = head;
bool flag = false;
for (;p;p = p->next,q=q->next) {
if (p->value == value) {
q->next = p->next;
delete p;
flag = true;
head->value--;
break;
}
}
if (!flag) {
cout << "链表中不存在值为:" << value << "的节点" << endl;
}
}
void LinkList::deleteByValueAll(int value) {
Node* p = head->next;
Node* q = head;
bool flag = false;
while(p){
if (p->value == value) {
q->next = p->next;
Node* temp = p;
p = p->next; //此处q不动,留给你们思考,不会再留言,嘻嘻
delete temp;
head->value--;
flag = true;
}
else {
p = p->next;
q = q->next;
}
}
if (!flag) {
cout << "链表中不存在值为:" << value << "的节点" << endl;
}
}
void LinkList::editByIndex(int index,int value) {
if (index == 0) {
cout << "不能修改头节点!" << endl;
return;
}
Node* p = findByIndex(index);
if (!p) {
cout << "修改失败!" << endl;
return;
}
else {
p->value = value;
}
}
void LinkList::print() {
for (Node* p = head->next;p;p = p->next) {
cout << p->value << " ";
}
cout << endl;
}
测试函数
main.cpp
#include"head.h"
void printAnswer(LinkList linklist) {
linklist.print();
cout << "当前长度:";
cout << linklist.getLength() << endl;
}
int main() {
int n;
cout << "请输入节点个数:";
cin >> n;
LinkList linklist;
linklist.create();
int num;
while (n--) {
cin >> num;
linklist.insertHead(new Node(num));
}
cout << "头插法结果:";
printAnswer(linklist);
cout << "尾插一个数:";
cin >> num;
linklist.insertTail(new Node(num));
cout << "尾插法结果:";
printAnswer(linklist);
cout << "想删除第几个:";
cin >> num;
linklist.deleteByIndex(num);
cout << "删除结果:";
printAnswer(linklist);
cout << "输入你想删除值为多少的节点(只删除首个):";
cin >> num;
linklist.deleteByValueOnce(num);
cout << "删除结果:";
printAnswer(linklist);
cout << "输入你想删除值为多少的节点(所有的):";
cin >> num;
linklist.deleteByValueAll(num);
cout << "删除结果:";
printAnswer(linklist);
int replace;
cout << "输入你想修改第几个节点并改成值为多少:";
cin >> num >> replace;
linklist.editByIndex(num, replace);
cout << "修改结果:";
printAnswer(linklist);
}
测试结果
总结
链表的操作有很多,以后遇见了再进行补充。