单链表的创建与使用

头文件声明

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
using namespace std;

类型声明

typedef int ElementType; // 数据的类型应由用户决定

结构体声明

typedef struct Node
{
	ElementType data;
	struct Node *next;
}Node;
typedef struct Node *LinkList;

创建单链表

  • 头插法算法思路
  1. 声明一个指针p用于不断生成新结点
  2. 初始化一个空链表L
  3. 让L的头结点的指针指向NULL,即建立一个带头结点的单链表
  4. 循环:
    • 生成一个新结点并赋值给p
    • 随机生成一个数字赋值给p->data
    • 将p插入到头结点与前一结点之间
  • 算法实现
/*随机产生n个元素的值,建立带表头结点的单链线性表L(头插法,栈)*/
void CreateListHead(LinkList *L,int n) {
	LinkList p;
	srand(time(0));
	*L = (LinkList)malloc(sizeof(Node));
	(*L)->next = NULL; // 建立一个带头结点的单链表
	for(int i = 0; i < n; i++) {
		p = (LinkList)malloc(sizeof(Node)); // 生成新结点
		p->data = rand()%100+1; // 随机生成100以内的数字
		p->next = (*L)->next; // 将L的后继结点(头结点)赋值给p(新结点)的后继
		(*L)->next = p; // 插入到表头
	}
}
  • 尾插法算法实现
/*随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法,队列)*/
void CreateListTail(LinkList *L, int n) {
	LinkList p,tail;
	srand(time(0));
	*L = (LinkList)malloc(sizeof(Node));
	tail = *L; // tail为指向尾部的结点
	for(int i = 0; i < n; i++) {
		p = (Node *) malloc(sizeof(Node));
		p->data = rand() % 100 +1;
		tail->next = p; // 将表尾终端结点的指针指向新结点
		tail = p; // 将当前的新结点定义为表尾终端结点
	}
	tail->next = NULL; // 循环结束后,将当前结点的指针域置空,表示当前链表结束
}

删除链表

  • 算法思路
  1. 声明一结点p和q
  2. 将第一个结点赋值给p
  3. 循环:
    • 将下一结点赋值给q
    • 释放p
    • 将q赋值给p
  • 算法实现
/*单链表的整表删除*/
bool ClearList(LinkList *L) {
	LinkList p,q;
	p = (*L)->next; // p指向第一个结点
	while(p) {
		q = p->next;
		free(p);
		p = q;
	}
	(*L)->next = NULL;
	return true;
}

说明: q指针的必要性。p是一个结点,有数据域和指针域,当直接将p指针free掉而不将p的指针域保留下来的时候,其指针域将会被一起free,q的作用就是用来记录保存下一结点的。

查找元素

  • 算法思路
  1. 声明一个指针p指向链表的第一个结点,初始化j从1开始
  2. 当j<i时,遍历链表,让p的指针向后移动,不断指向下一结点,j累加1
  3. 若到链表末尾时p为空,则说明第i个结点不存在
  4. 否则说明查找成功,返回结点p的数据
  • 算法实现
/*返回L中第i个元素的值*/
ElementType GetElem(LinkList *L, int i) {
	int j;
	ElementType e;
	LinkList p;
	p = (*L)->next; // 让p指向链表L的第一个结点
	j = 1; // 计数器
	while(p && j < i) { // 当p不为空且计数器j没有等于i时
		p = p->next;
		++j;
	}
	if (!p || j > i) // 第i个结点不存在
		return 0;
	e = p->data;
	return e;
}

元素的插入

  • 算法思路
  1. 声明一个指针p指向链表头结点,初始化j从1开始
  2. 当j<i时,遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1d
  3. 若到链表末尾p为空,则说明第i个结点不存在
  4. 否则说明查找成功,在系统中生成一个空结点s
  5. 将数据元素e赋值给s->data
  6. 单链表的插入标准语句:s->next = p->next;p->next = s;
  7. 注意:上述语句顺序不能调转
  • 算法实现
/*在L中第i个结点位置之前插入新的数据元素e,L的长度加1*/
bool ListInsert(LinkList *L, int i, ElementType e) {
	int j;
	LinkList p,s;
	p = *L;
	j = 1;
	while(p && j < i) {
		p = p->next;
		++j;
	}
	if (!p || j > i)
		return false;
	s = (LinkList)malloc(sizeof(Node)); // 生成新结点
	s->data = e;

	/*开始插入新结点*/
	s->next = p->next; // 将p的后继结点赋值给s的后继
	p->next = s; // 将s赋值给p的后继
	return true;
}

元素的删除

  • 算法思路
  1. 声明一个指针p指向链表头指针,初始化j从1开始
  2. 当j<i时,遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1
  3. 若到链表末尾时p为空,则说明第i个结点不存在
  4. 否则说明查找成功,将欲删除的结点p->next赋值给q
  5. 单链表的删除标准语句:p->next = q->next;
  6. 释放q结点(这样就达到了删除q结点即p的后继结点的目的)
  • 算法实现
/*删除L的第i个结点,并用e返回其值,L的长度减1*/
bool ListDelete(LinkList *L, int i) {
	LinkList p,q;
	int j;
	p = *L;
	j = 1;
	while(p->next && j < i) { // 遍历寻找第i-1个结点
		p = p->next;
		++j;
	}
	if (!(p->next) || j > i)
		return false;
	
	/*开始删除第i个结点*/
	q = p->next; 
	p->next = q->next; // 将q的后继结点赋值给p的后继
	free(q);
	return true;
}

整表打印

/*单链表的整表打印*/
void ListPrint(LinkList *L) {
	LinkList p = *L;
	int j = 1;
	while(p->next) {
		p = p->next;
		cout<<p->data<<" ";
		++j;
	}
}

完整源码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
using namespace std;

typedef int ElementType;

typedef struct Node
{
	ElementType data;
	struct Node *next;
}Node;
typedef struct Node *LinkList;

/*返回L中第i个元素的值*/
ElementType GetElem(LinkList *L, int i) {
	int j;
	ElementType e;
	LinkList p;
	p = (*L)->next; // 让p指向链表L的第一个结点
	j = 1; // 计数器
	while(p && j < i) { // 当p不为空且计数器j没有等于i时
		p = p->next;
		++j;
	}
	if (!p || j > i) // 第i个结点不存在
		return 0;
	e = p->data;
	return e;
}

/*在L中第i个结点位置之前插入新的数据元素e,L的长度加1*/
bool ListInsert(LinkList *L, int i, ElementType e) {
	int j;
	LinkList p,s;
	p = *L;
	j = 1;
	while(p && j < i) {
		p = p->next;
		++j;
	}
	if (!p || j > i)
		return false;
	s = (LinkList)malloc(sizeof(Node)); // 生成新结点
	s->data = e;

	/*开始插入新结点*/
	s->next = p->next; // 将p的后继结点赋值给s的后继
	p->next = s; // 将s赋值给p的后继
	return true;
}

/*删除L的第i个结点,并用e返回其值,L的长度减1*/
bool ListDelete(LinkList *L, int i) {
	LinkList p,q;
	int j;
	p = *L;
	j = 1;
	while(p->next && j < i) { // 遍历寻找第i-1个结点
		p = p->next;
		++j;
	}
	if (!(p->next) || j > i)
		return false;
	
	/*开始删除第i个结点*/
	q = p->next; 
	p->next = q->next; // 将q的后继结点赋值给p的后继
	free(q);
	return true;
}

/*随机产生n个元素的值,建立带表头结点的单链线性表L(头插法,栈)*/
void CreateListHead(LinkList *L,int n) {
	LinkList p;
	srand(time(0));
	*L = (LinkList)malloc(sizeof(Node));
	(*L)->next = NULL; // 建立一个带头结点的单链表
	for(int i = 0; i < n; i++) {
		p = (LinkList)malloc(sizeof(Node)); // 生成新结点
		p->data = rand()%100+1; // 随机生成100以内的数字
		p->next = (*L)->next; // 将L的后继结点(头结点)赋值给p(新结点)的后继
		(*L)->next = p; // 插入到表头
	}
}

/*随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法,队列)*/
void CreateListTail(LinkList *L, int n) {
	LinkList p,tail;
	srand(time(0));
	*L = (LinkList)malloc(sizeof(Node));
	tail = *L; // tail为指向尾部的结点
	for(int i = 0; i < n; i++) {
		p = (Node *) malloc(sizeof(Node));
		p->data = rand() % 100 +1;
		tail->next = p; // 将表尾终端结点的指针指向新结点
		tail = p; // 将当前的新结点定义为表尾终端结点
	}
	tail->next = NULL; // 循环结束后,将当前结点的指针域置空,表示当前链表结束
}

/*单链表的整表删除*/
bool ClearList(LinkList *L) {
	LinkList p,q;
	p = (*L)->next; // p指向第一个结点
	while(p) {
		q = p->next;
		free(p);
		p = q;
	}
	(*L)->next = NULL;
	return true;
}

/*单链表的整表打印*/
void ListPrint(LinkList *L) {
	LinkList p = *L;
	int j = 1;
	while(p->next) {
		p = p->next;
		cout<<p->data<<" ";
		++j;
	}
}

int main() 
{
	LinkList *L;
	L = (LinkList*)malloc(sizeof(Node));
	int n;
	cout<<"Please input the size of the linklist that you want to create: ";
	cin>>n;

	/*单链表的初始化(用尾插法建立单链表)*/
	CreateListTail(L,n);
	cout<<"The linklist: "<<endl;
	ListPrint(L);
	cout<<endl;

	/*测试GetElem函数*/
	cout<<"Please input the number: ";
	int i;
	cin>>i;
	cout<<"The "<<i<<"th element is: ";
	cout<<GetElem(L,i)<<endl;

	
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿彬y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值