##链表(一)单列表的创建与基本功能实现
单链表创建的算法思路:
1、声明一指针p和计数器变量
2、初始化一空链表L
3、让L的头结点的指针指向NULL,即建立一个带头结点的单链表
4、循环:
生成一新结点赋值给p;
随机生成一数字赋值给p的数据域p->data;
将p插入到头结点与前一新节点之间(头插)
将p插入到最后一个结点之后(尾插)
head.h
#pragma once
#include <iostream>
using namespace std;
//结点
struct Node {
int value;//结点值
Node* next;//结点的next指针
};
class LinkList {
public:
LinkList(); //构造函数
~LinkList(); //析构函数
void insertHead(int data); //头插法
void insertTail(int data); //尾插法
Node* findByIndex(int); //根据索引查找节点,并返回节点的指针,注意0返回头节点
Node* findByValue(int); //根据值查找节点,并返回节点的指针
int getLength(); //获取链表的长度
void deleteByIndex(int); //根据索引删除节点
void deleteByValueOnce(int); //根据节点值删除第一个节点
void editByIndex(int, int); //根据索引修改节点的值
void printlist();//遍历
private:
Node* head; //头节点指针,value用于存放链表的长度
};
构造函数
进行链表类中头结点的构造(本例中写的单链表有头结点,其实有没有头结点差别不大)
LinkList::LinkList()
{
head = new Node;
head->next = NULL;
head->value = 0;
}
析构函数
LinkList::~LinkList()//将所有开辟在堆区的结点释放
{
if (head)
{
Node* tmp = head;
head = head->next;
delete tmp;
}
}
头插法
void LinkList::insertHead(int data)
{
/*头插法不介意此时的链表是否为空,因为本例的单链表是带头结点的,如果链表为空,那么head->next==NULL;将它赋给p->next正合逻辑*/
Node* p = new Node;//此处的p是开辟在堆区的
p->next = head->next;//先保持原来链表,将新结点的next指向head的next
head->next = p;//断开head与head->next的连接,将head->next指向p
p->value = data;//赋值语句
head->value++;//用head->value来储存数组长度
}
尾插法
void LinkList::insertTail(int data)_
{
Node* newnode = new Node;//newnode开辟在堆区
if (head->next==NULL)//空表(此时与头插法相同,可以直接调用头插法函数)
{
newnode->value = data;
newnode->next = NULL;//最后一个结点的next指向NULL;
head->next = newnode;//空表尾插法的第一个节点就是head的下一个结点
head->value++;//长度加一
}
else
{
Node* p = head;//这里的p不可以delete,它是开辟在栈区的,此时它就是head,将它delete,那么就会将head也delete掉
int i = head->value;//取当前链表的最后一个结点,并赋给p
while (i-- && p->next != NULL)
{
p = p->next;
}
newnode->value = data;
newnode->next = p->next;//新结点的next指向最后一个结点的next即NULL
p->next = newnode;//将新节点连接到链表的最后一个元素上
head->value++;
}
}
获取链表长度
int LinkList::getLength()
{
return head->value;
}
#根据索引查找节点,并返回节点的指针,注意0返回头节点
Node* LinkList::findByIndex(int index)
{
Node* p = head;
if (index < 0||index>getLength())
{
cout << "索引非法!" << endl;
return NULL;
}
if (index == 0)
{
return head;
}
while (index--)
{
p = p->next;
}
return p;
}
通过值查找,并返回该节点
Node* LinkList::findByValue(int value)
{
Node* p = head;
while (p != NULL && p->next != NULL)//如果是p!=NULL,那么p = p->next会将p置空,编译器会报错,空指针是不存在value的
{
p = p->next;
if (p->value == value)
{
return p;
}
}
return NULL;
}
根据索引删除节点
void LinkList::deleteByIndex(int index)
{
if (index == 0)
{
cout << "不能删除头节点!" << endl;
return;
}
Node* p = findByIndex(index-1);//返回要删除节点的前一结点
Node* tmp = p->next;//将要删除结点存放到temp中
if (p->next->next == NULL)//删除尾结点(注意:拿到的是要删除节点的前一结点)
{
p->next = NULL;
delete temp;//释放删除结点
}
else//非尾结点
{
p->next = p->next->next;
delete tmp;
}
head->value--;
}
根据节点值删除节点
void LinkList::deleteByValueOnce(int value)
{
Node* p = head;
while(p != NULL && p->next != NULL)/如果没有这两个条件,p->next和p->next->next会报错
{
if (p->next->value == value)
{
p->next = p->next->next;
head->value--;
}
else
{
p = p->next;
}
}
}
根据索引修改节点的值
void LinkList::editByIndex(int pos, int value)
{
if (pos == 0)
{
cout << "不能修改头节点!" << endl;
return;
}
Node* p = findByIndex(pos);//调用前面的查找结点函数
if (p)
{
p->value = value;
}
}
遍历
void LinkList::printlist()
{
Node* p = head;
while (p != NULL&&p->next!=NULL)
{
p = p->next;
cout << p->value << " ";
}
cout << endl;
}
测试代码
int main()
{
LinkList LC;
LC.insertHead(1);
LC.insertHead(2);
LC.insertHead(3);
LC.insertHead(4);
//cout << LC.findByIndex(3)->value << endl;
LC.insertTail(10);
LC.insertTail(20);
LC.insertTail(30);
LC.insertTail(40);
LC.insertTail(40);
LC.insertTail(40);
//cout << LC.getLength() << endl;
//cout << LC.findByValue(40)->value << endl;
LC.printlist();
//LC.deleteByIndex(7);
cout << LC.getLength() << endl;
LC.deleteByValueOnce(40);
cout << LC.getLength() << endl;
LC.printlist();
LC.editByIndex(7, 100);
LC.printlist();
}
完整代码
#include"head.h"
LinkList::LinkList()
{
head = new Node;
head->next = NULL;
head->value = 0;
}
LinkList::~LinkList()
{
if (head)
{
Node* tmp = head;
head = head->next;
delete tmp;
}
}
void LinkList::insertHead(int data)//头插法(已验证)
{
Node* p = new Node;
p->next = head->next;
head->next = p;
p->value = data;
head->value++;
}
void LinkList::insertTail(int data)//尾插法(已验证)_
{
Node* p = head;
Node* newnode = new Node;
if (head->next==NULL)
{
newnode->value = data;
newnode->next = NULL;
head->next = newnode;
head->value++;
}
else
{
int i = head->value;
while (i-- && p->next != NULL)
{
p = p->next;
}
newnode->value = data;
newnode->next = p->next;
p->next = newnode;
head->value++;
}
}
int LinkList::getLength() //获取链表长度(已验证)
{
return head->value;
}
Node* LinkList::findByIndex(int index)//根据索引查找节点,并返回节点的指针,注意0返回头节点(已验证)
{
Node* p = head;
if (index < 0||index>getLength())
{
cout << "索引非法!" << endl;
return NULL;
}
if (index == 0)
{
return head;
}
while (index--)
{
p = p->next;
}
return p;
}
Node* LinkList::findByValue(int value)//通过值查找,并返回该节点(已验证)
{
Node* p = head;
while (p != NULL && p->next != NULL)
{
p = p->next;
if (p->value == value)
{
return p;
}
}
return NULL;
}
void LinkList::deleteByIndex(int index) //根据索引删除节点(已验证)
{
if (index == 0)
{
cout << "不能删除头节点!" << endl;
return;
}
//Node* q= findByIndex(index);
Node* p = findByIndex(index-1);
Node* tmp = p->next;
if (p->next->next == NULL)//删除尾结点
{
p->next = NULL;
delete tmp;
}
else//非尾结点
{
p->next = p->next->next;
delete tmp;
}
head->value--;
}
void LinkList::deleteByValueOnce(int value) //根据节点值删除节点
{
Node* p = head;
while(p != NULL && p->next != NULL)
{
if (p->next->value == value)
{
p->next = p->next->next;
head->value--;
}
else
{
p = p->next;
}
}
}
void LinkList::editByIndex(int pos, int value) //根据索引修改节点的值
{
if (pos == 0)
{
cout << "不能修改头节点!" << endl;
return;
}
Node* p = findByIndex(pos);
if (p)
{
p->value = value;
}
}
void LinkList::printlist()//遍历(已验证)
{
Node* p = head;
while (p != NULL&&p->next!=NULL)
{
p = p->next;
cout << p->value << " ";
}
cout << endl;
}
int main()
{
LinkList LC;
LC.insertHead(1);
LC.insertHead(2);
LC.insertHead(3);
LC.insertHead(4);
//cout << LC.findByIndex(3)->value << endl;
LC.insertTail(10);
LC.insertTail(20);
LC.insertTail(30);
LC.insertTail(40);
LC.insertTail(40);
LC.insertTail(40);
//cout << LC.getLength() << endl;
//cout << LC.findByValue(40)->value << endl;
LC.printlist();
//LC.deleteByIndex(7);
cout << LC.getLength() << endl;
LC.deleteByValueOnce(40);
cout << LC.getLength() << endl;
LC.printlist();
LC.editByIndex(7, 100);
LC.printlist();
}
链表最重要的是搞清楚逻辑和添加结点和删除节点的指针修改顺序,在删除结点时,释放被删除结点,记住,只有new出来的变量才可以delete,栈区变量不可以delete。