链表的学习(浅)

什么是链表?---链表是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构。链表和数组比较,不用事先确定存储空间,而是根据需要开辟内存单元。
å¾ä¸

单链表的结点结构

struct node* next是结构体指针,指向下一个结构体

typedef struct node
{
	int data;//数据域
	struct node* next;//指针域
}Node,*Link;//Node为struct node的别名,*Link为指向结构体的指针

初始化单链表

1.创建一个头结点,如果内存分配失败,则返回NULL,如果创建成功,则让head指向NULL

(此时没有下一个结点)

2.返回一个头结点

Link creatList()
{
	Link head = new Node;//分配头结点
	if (head == NULL)//内存不足,返回失败
	{
		return NULL;
	}
	else
	{
		head->next = NULL;//头结点的下一结点暂时不存在,置空
	}
	return head;
}

单链表的定向插入

为了保证头指针不变,每次实行操作时,都要把head指针复制一份,作为此函数的工作指针(来遍历链表);

i为插入的位置(从0开始),x为插入的数据;

1.为了找到正确的位置,需要设置一个count来计数,直到工作指针移动到i-1位(因为从0开始,所以是i-1位)停止,进行插入操作;同时要保证p指针不为空(若为空无法插入,因为没有结点存在)

2.如果p从头结点移动到NULL也没有找到第i-1位,则返回0,插入失败;

3.如果找到了第i-1位,则为了插入目标数据,新创建一个结点来存放该数据(node->data=x);

并且让工作指针p的下一个结点与新建立结点node相联系node->next=p->next;

再让p与新建立的结点node相联系p->next=node;

bool insertNode(Link head,int i,int x)
{
	Link p = head;//工作指针指向头结点
	int count = 0;
	if (i < 1)
	{
		return 0;
	}
	while (p != NULL && count < i - 1)//p移动到第i-1个结点
	{
		p = p->next;
		count++;
	}
	if (p == NULL)//没有找到第i-1个结点
		return 0;
	else
	{
		Link node1 = new Node;//建立新的结点
		node1->data = x;//插入的值
		node1->next = p->next;
		p->next = node1;
		return 1;
	}
}

 头插法

无需遍历链表,所以不需要设置工作指针;

直接新创建一个结点,让头结点的下一个结点与新结点进行联系,并将x赋给新结点

bool HaddNode(Link head, int x)
{
	Link p = new Node;//创建新的结点
	if (head == NULL)
	{
		return 0;
	}
	else
	{
		Link p = new Node;
		p->next = head->next;
		head->next = p;
		p->data = x;
		return 1;
	}
}

 尾插法

因为要遍历链表到最后一个结点,为了保证头指针不变,需要设立工作指针tmp来遍历链表;

让tmp移动到最后一个结点上,只有到下一个结点为空(不存在),才可以实现尾插;

即创建一个新的结点p,让工作指针tmp(此时已经移动到最后一个结点上了)指向新创建的结点p,并将数据赋给p->data,再将p->next=NULL;使之成为(新的)最后一个结点。

bool addNode(Link head, int x)
{
	Link p = new Node;//创建新的结点
	Link tmp = head;
	if (head == NULL)
	{
		return 0;
	}
	while (tmp->next!= NULL)//下一个为空,才能成为结点
	{
		tmp = tmp->next;
	}
	tmp->next = p;
    p->data = x;
	p->next = NULL;
	return 1;
}

单链表的定向删除

建立两个工作指针来遍历链表(一前一后)

只要后指针p不为NULL,并且没有找到要删除的结点,则前后指针都往后移一位

若找到要删除的结点,则改变要删除结点前后结点的指针指向关系

让前指针q指向被删除的结点p的下一个,建立起链接关系,再delete要删除的结点p

bool deleteNode(Link head, int x)
{
	if (head == NULL || head->next == NULL)//若链表为空表
	{
		return false;
	}
    Link q = head;
	Link p = head->next;//使得q在前,p在后
	while (p != NULL)
	{
		if (p->data == x)
		{
			q->next = p->next;//找到对应的结点,删除并且提返回
			delete p;
			return true;
		}
		else//没有找到相应的结点,q往后移,p往后移
		{
			q = p;
			p = p->next;
		}
	}
	return false;//循环结束了,说明没有找到相应的结点
}

顺序删除

bool HdeleteNode(Link head)
{
	if (head == NULL)
	{
		return 0;
	}
	else
	{
		Link p = head->next;//获得第一个结点
		head->next = p->next;//调整头结点与第二个结点的联系,使之成为第一个结点(删除后)
		delete p;//删除第一个结点
		return 1;
	}
}

逆序删除

bool WdeleteNode(Link head)
{
	if (head == NULL)
	{
		return 0;
	}
	else
	{
		Link p = head;
		Link q = head->next;
		while (q->next != NULL)//让q移动到最后一个结点,p移动到倒数第二个结点,再删除最后一个结点q
		{
			p = p->next;
			q = q->next;
		}
		delete q;
		p->next = NULL;//重新定义最后一个结点
		return 1;
	}
}

单链表的释放

若头指针head=NULL则为空链表,无法释放;否则只要head结点指向的下一个结点不为NULL,就进行释放结点

从第一个结点开始释放,为了将链表内所有结点都释放完,需要设置工作指针q=head来遍历链表;并且头结点head移动到下一个结点上(head->next),然后将工作指针q(原始头结点)删除,达到释放结点的目的

bool clearLink(Link head)
{
	if (head == NULL)
	{
		return 0;
	}
	while (head->next != NULL)
	{
		Link q = head;//先让q指向head
		head = head->next;//head指向下一个结点
		delete q;
	}
	head->next=NULL;
	return 1;
}

单链表数据的查询

保证头结点不改变,需要设立工作指针p来遍历链表

bool queryNode(Link head, int x)//x为待查找的数据
{
	Link p = head->next;//从第一个数据结点开始
	while (p != NULL)
	{
		if (p->data == x)
		{
			return 1;
		}
		else
			p = p->next;
	}
	return 0;
}

单链表的长度

也可以在头结点里的data域设置一个len,每创建一个结点就head->len++

为了保证头指针不变,需要设立一个工作指针p来遍历链表

int length(Link head)
{
	if (head == NULL)
	{
		return 0;
	}
	Link p = head->next;
	int count = 0;
	while (p != NULL)
	{
		count++;
		p = p->next;
	}
	return count;
}

单链表的显示

为了保证头指针不变,需要设立工作指针p来遍历链表,只有p不为NULL,就输出数据域,并将p指向p的下一个结点

void displayNode(Link head)//传入头指针
{
	Link p = head->next;//获得第一个数据结点
    if(head==NULL||head->next==NULL)
    {
        cout<<"该链表不存在"<<endl;
    }
	while (p != NULL)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}

完整的单链表

#include<iostream>
using namespace std;

typedef struct node
{
	int data;
	struct node* next;
}Node,*Link;
//初始化链表
Link creatList()
{
	Link head = new Node;
	head->next = NULL;
	//head->data = 0;
	return head;
}
//头插法
bool HaddNode(Link head, int x)
{
	if (head == NULL)
	{
		return 0;
	}
	else
	{
		Link p = new Node;
		p->next = head->next;
		head->next = p;
		p->data = x;
		return 1;
	}
}
//尾插法
bool WaddNode(Link head, int x)
{
	Link p = new Node;
	Link tmp = head;
	if (head == NULL)
	{
		return 0;
	}
	else
	{
		while (tmp->next != NULL)
		{
			tmp = tmp->next;
		}
		tmp->next = p;
		p->next = NULL;
		p->data = x;
		return 1;
	}
}
//定向插入
bool insertNode(Link head, int i, int x)
{
	if (head == NULL)
	{
		return 0;
	}
	else
	{
		Link p = head;
		int count = 0;
		while (p != NULL && count < i - 1)
		{
			Link Xnode = new Node;
			Xnode->next = p->next;
			p->next = Xnode;
			Xnode->data = x;
			return 1;
		}
	}
}
//顺序删除
bool HdeleteNode(Link head)
{
	if (head == NULL)
	{
		return 0;
	}
	else
	{
		Link p = head->next;//获得第一个结点
		head->next = p->next;//调整头结点与第二个结点的联系,使之成为第一个结点(删除后)
		delete p;//删除第一个结点
		return 1;
	}
}
//逆序删除
bool WdeleteNode(Link head)
{
	if (head == NULL)
	{
		return 0;
	}
	else
	{
		Link p = head;
		Link q = head->next;
		while (q->next != NULL)//让q移动到最后一个结点,p移动到倒数第二个结点,再删除最后一个结点q
		{
			p = p->next;
			q = q->next;
		}
		delete q;
		p->next = NULL;//重新定义最后一个结点
		return 1;
	}
}
//定向删除
bool deleteNode(Link head,int i)
{
	if (head == NULL)
	{
		return 0;
	}
	else
	{
		int count = 0;
		Link p = head;
		Link q = head->next;
		while (q!=NULL)
		{
			if (count < i - 1)// 没有找到相应的位置,两个工作指针同时往后移
			{
				p = p->next;
				q = q->next;
				count++;
			}
			else//如果找到相应的位置
			{
				p->next = q->next;
				delete q;
				return 1;
			}
			
		}
		return 0;//循环结束了,但是没有找到相应的结点
	}
}
//链表长度
int getLenth(Link head)
{
	int len = 0;
	Link p = head;
	while (p != NULL)
	{
		len++;
		p = p->next;
	}
	return len;
}
//打印链表
void print(Link head)
{
	if (head == NULL)
	{
		cout << "空链表" << endl;
	}
	else
	{
		Link p = head;
		while (p->next != NULL)
		{
			cout << p->next->data << " ";
			p = p->next;
		}
		cout << endl;
	}
}
//链表查询
bool querry(Link head,int x)
{
	if (head == NULL)
	{
		return 0;
	}
	else
	{
		Link p = head;
		while (p != NULL)
		{
			if (p->data == x)
				return 1;
			else
				p = p->next;
		}
		return 0;
	}
}
//链表释放
void clearList(Link head)
{
	if (head == NULL)
	{
		cout << "链表已经为空,无需释放" << endl;
	}
	else
	{
		
		while (head->next != NULL)
		{
			Link p = head;
			head = p->next;
			delete p;
		}
		head->next = NULL;
	}
}
int main()
{
	Link head = creatList();
	int n;
	cin >> n;


	cout << "头插法---逆序" << endl;
	for (int i = 0; i < n; i++)
	{
		HaddNode(head, i);
	}
	print(head);


	cout << "尾插法---顺序" << endl;
	for (int i = 0; i < n; i++)
	{
		WaddNode(head, i);
	}
	print(head);


	cout << "顺序删除(删除第一个)" << endl;
	HdeleteNode(head);
	print(head);

	cout << "逆序删除(删除最后一个)" << endl;
	WdeleteNode(head);
	print(head);


	cout << "定向删除" << endl;
	cout << "请输入要删除的序号:";
	int x;
	cin >> x;
	deleteNode(head, x);
	print(head);
	cout << "请输入要查询的数据:";
	int a;
	cin >> a;
	if (querry(head, a))
	{
		cout << 1 << endl;
	}
	else
	{
		cout << 0 << endl;
	}
	clearList(head);

}

双链表

在处理时间方面:双向链表的插入与删除操作比单链表的时间要快很多。在最末尾插入的时候,单链表需要找到需要插入位置的前一个节点,需要遍历整个链表,时间复杂度为O(n),而双向链表只需要head->tail,就可以得到最后一个节点的位置,然后就可以进行插入操作,时间复杂度为O(1)。在删除操作方面,单链表需要遍历到需要删除的节点的前一个节点,双向链表需要遍历到需要删除的节点,时间复杂度同为O(n)
 

双链表结点结构

typedef struct node
{
	int data;
	struct node* pre;//前指针
	struct node* next;//后指针
}Node, * Link;

双链表的创建

pre为前指针,next为后指针

data记录链表的长度即元素的个数

Link creatList()
{
	Link head = new Node;//创建头结点
    head->pre = NULL;
	head->next = NULL;
    head->data = 0;//头结点的data域来记录链表中有多少个元素
	return head;
}

头插法

若链表为空,则新创建的结点node的next就指向NULL;新结点node的pre前指针指向head,

head的next指向node;head的data++,结点增加即长度增加

若链表不为空,则新创建的结点node的pre前指针指向head;新结点node的next后指针指向头结点的下一个即head->next再让head->next的前指针pre指向新结点node;再让头指针head指向新结点node

void headInsert(Link head, int x)//头结点的data域来记录有多少个元素
{
	Link node = new Node;
	node->data = x;
	if (head->data == 0 )
	{
		//链表为空
        node->pre = head;//前指针指向头结点
		node->next = NULL;//因为是空表,所以node->next=head->next=NULL
		head->next = node;
        head->data++;//头结点的data域来记录链表中有多少个元素
	}
	else
	{
		node->pre = head;//前指针指向头结点
		node->next = head->next;//后指针指向头结点的next
		head->next->pre = node;//头结点的next指向下一个,下一个的pre指向新结点
		head->next = node;//头结点的next指向新结点
        head->data++;//头结点的data域来记录链表中有多少个元素
	}
}

尾插法

设置工作指针,找到最后一个结点

再改变pre和next指针之间的指向关系

即让最后一个结点p赋给新结点node的pre前指针;p的next赋给新结点node的next;再让node赋给p的next

void tailInsert(Link head, int x)
{
	Link p = head;//设置工作指针
	Link node = new Node;//创建新结点
	node->data = x;
	while (p->next != NULL)//找到最后一个结点,next指向NULL
	{
		p = p->next;
	}
	node->pre = p;//node的前指针指向p
	node->next = p->next;//node的后指针指向p的next即为NULL
	p->next = node;//p的后指针指向node(新建立在最后的结点)
	head->data++;
}

删除结点(以值来删除)

bool deleteNode(Link head, int x)
{
	Link node = head->next;//设置工作指针
	while (node != NULL)
	{
		if (node->data == x)//找到要删除的node结点
		{
			node->pre->next = node->next;//前一个结点的next指向node的next
			node->next->pre = node->pre;//后一个结点的pre指向前一个结点
			delete node;
			return 1;
		}
		node = node->next;
	}
	return 0;
}

删除结点(以下标删除)

bool deleteNodeX(Link head, int i)
{
	Link p = head->next;//设置工作指针
	int count = 0;//计数
	while (p != NULL)
	{
		if (count == i)
		{
			p->pre->next = p->next;//p的后指针赋给p前指针的next
			p->next->pre = p->pre;//p的前指针赋给p->next的前指针
			delete p;
			return 1;
		}
		else
		{
			p = p->next;
			count++;
		}
	}
	return 0;
}

打印双链表

void printList(Link head)
{
	Link node = head->next;//设置工作指针
	while (node != NULL)
	{
		cout << node->data << " ";
		node = node->next;
	}
    cout << endl;
}

完整的双链表

#include<iostream>
using namespace std;
typedef struct node
{
	int data;
	struct node* pre;//前指针
	struct node* next;//后指针
}Node, * Link;
Link creatList()
{
	Link head = new Node;//创建头结点
	head->pre = NULL;
	head->next = NULL;
	head->data = 0;//头结点的data域来记录链表中有多少个元素
	return head;
}
void headInsert(Link head, int x)//头结点的data域来记录有多少个元素
{
	Link node = new Node;
	node->data = x;
	if (head->data == 0)
	{
		//链表为空
		node->pre = head;//前指针指向头结点
		node->next = NULL;//因为是空表,所以node->next=head->next=NULL
		head->next = node;
		head->data++;//头结点的data域来记录链表中有多少个元素
	}
	else
	{
		node->pre = head;//前指针指向头结点
		node->next = head->next;//后指针指向头结点的next
		head->next->pre = node;//头结点下一个的前指针指向新结点
		head->next = node;//头结点指向新结点
		head->data++;//头结点的data域来记录链表中有多少个元素
	}
}
void printList(Link head)
{
	Link node = head->next;//设置工作指针
	while (node != NULL)
	{
		cout << node->data << " ";
		node = node->next;
	}
	cout << endl;
}
void tailInsert(Link head, int x)
{
	Link p = head;//设置工作指针
	Link node = new Node;//创建新结点
	node->data = x;
	while (p->next != NULL)//找到最后一个结点,next指向NULL
	{
		p = p->next;
	}
	node->pre = p;//node的前指针指向p
	node->next = p->next;//node的后指针指向p的next即为NULL
	p->next = node;//p的后指针指向node(新建立在最后的结点)
	head->data++;
}
//删除值
bool deleteNodeZ(Link head, int x)
{
	Link p = head->next;//设置工作指针
	while (p != NULL)
	{
		if (p->data == x)//找到要删除的p结点
		{
			p->pre->next = p->next;//前一个结点的next指向p的next
			p->next->pre = p->pre;//后一个结点的pre指向前一个结点
			delete p;
			return 1;
		}
		p = p->next;
	}
	return 0;
}
//删除下标
bool deleteNodeX(Link head, int i)
{
	Link p = head->next;//设置工作指针
	int count = 0;//计数
	while (p != NULL)
	{
		if (count == i)
		{
			p->pre->next = p->next;//p的后指针赋给p前指针的next
			p->next->pre = p->pre;//p的前指针赋给p->next的前指针
			delete p;
			return 1;
		}
		else
		{
			p = p->next;
			count++;
		}
	}
	return 0;
}
int main()
{
	Link head = creatList();
	for (int i = 0; i < 5; i++)
	{
		headInsert(head, i);
	}
	printList(head);
	for (int i = 0; i < 5; i++)
	{
		tailInsert(head, i);
	}
	printList(head);
	int x;
	cin >> x;
	deleteNodeZ(head, x);
	printList(head);
	int n;
	cin >> n;
	deleteNodeX(head, n);
	printList(head);
	return 0;
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值