2021-08-05

##链表(一)单列表的创建与基本功能实现
单链表创建的算法思路:
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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值