数据结构系列之二单链表

1. 知识点回顾

顺序表和单链表区别:

        顺序表:(1)特点:长度固定且需要分配一段连续的存储空间,存储密度大,可以使用倍增(具体方法就是判断当前元素如果达到最大,重新开辟2*N的空间,如果当前元素为空间的1/4,可以缩小原来空间至1/2,每次操作的同时要复制原来的旧的元素到新的存储空间中)的方法来动态扩容,将顺序表变成"可变长度"。(2)优点:便于随机访问,时间复制度O(1)。(3)缺点:插入和删除需要移动大量的元素,时间复制度O(n)。

        单链表:(1)特点:长度不固定,可以任意增删;存储空间不连续,元素之间使用指针相连;存储密度小;(2)优点:插入和删除元素只需要修改指针,不需要移动元素,时间复制度O(1)。(3)缺点:访问元素都需要从链表头开始,时间复制度O(n)。

2. 单链表定义

链表又分为:单链表、循环链表、双向链表。单链表是由很多个结点组成(没有结点的链表就是空链表),每个结点都包含一个数据域和指针域,指针域指向的是紧邻的下一个结点,最后一个结点指针通常为NULL。单链表又分为有头结点和无头结点的单链表,本文主要讨论带头结点的单链表,在此必须清楚三个概念:开始结点、头指针、头结点。

开始结点:就是链表中的第一个结点,该结点没有直接前驱。

头指针:在没有头结点的前提下,头指针是指向开始结点的指针。有了头指针可以唯一确定一个单链表。

头结点:就是在链表开始结点之前再附加一个结点,头结点指针指向的结点数据域为空,有了头结点之后,头指针指向头结点,无论链表是否为空,头指针总是非空。有了头结点之后,对链表开始结点的操作和其他位置的结点操作是一样的。

语法难点:

因为头结点的指针本身就是个结构指针,所以在需要改变头结点的地方,函数的形参应该为指向头指针的指针。

如果这里不使用二级指针,会导致的问题就是我们已经给函数内分配了内存,但是在函数外却访问不到。

3. 单链表基本操作:

(1)void InitLinkedList(LinkedList* L):初始化一个单链表。

(2)void CreateLinkedList_Head(LinkedList* L,int n):头插法创建单链表。

(3)void CreateLinkedList_Tail(LinkedList* L, int n):尾插法创建单链表。

(4)int InsertLinkedList(LinkedList L, int i, DataType e):在第i个位置插入元素e。

(5)int DeleteElement(LinkedList L, int i):删除第i个位置的元素。

(6)void ClearLinkedList(LinkedList L):清理单链表,保留头结点。

(7)void DestroyLinkedList(LinkedList* L):销毁单链表。

(8)bool IsEmpty(LinkedList L):判断单链表是否为空。

(9)int GetLength(LinkedList L):获取单链表长度。

(10)LinkedList GetElement(LinkedList L, int i):查找第i个位置上的元素。

(11)void OutPut(LinkedList L):遍历输出单链表。

3.1 单链表结构体定义

//系统中已有此状态码定义,要防止冲突
#ifndef OVERFLOW
#define OVERFLOW    -2  //堆栈上溢
#endif

typedef int DataType;
//单链表结构体
typedef struct LNode
{
	DataType data;
	struct LNode* next;
}LNode;
typedef LNode* LinkedList;	//指向单链表结点的指针

3.2  初始化单链表

//初始化单链表
void InitLinkedList(LinkedList* L) {
	(*L) = (LinkedList)malloc(sizeof(LNode));
	if (!(*L))
	{
		exit(OVERFLOW);
	}
	(*L)->next = NULL;
}

3.3 头插法

//头插法
void CreateLinkedList_Head(LinkedList* L,int n) {
	int i;
	LinkedList p;
	DataType tmp;
	*L = (LinkedList)malloc(sizeof(LNode));
	if (!(*L))
	{
		exit(OVERFLOW);
	}
	(*L)->next = NULL;
	cout << "头插法建立单链表:\n" << endl;
	for (int i=1; i<=n; i++)
	{
		p = (LinkedList)malloc(sizeof(LNode));
		cout << "请输入第" << i << "个数:" << endl;
		cin >> tmp;
		p->data = tmp;
		p->next = (*L)->next;
		(*L)->next = p;
	}
}

3.4 尾插法

//尾插法
void CreateLinkedList_Tail(LinkedList* L, int n) {
	int i;
	LinkedList p, q;
	DataType tmp;
	*L = (LinkedList)malloc(sizeof(LNode));
	if (!(*L))
	{
		exit(OVERFLOW);
	}
	(*L)->next = NULL;
	q = *L;
	cout << "尾插法建立单链表:\n" << endl;
	for (int i=1; i<=n; i++)
	{
		p = (LinkedList)malloc(sizeof(LNode));
		cout << "请输入第" << i << "个数:" << endl;
		cin >> tmp;
		p->data = tmp;
		q->next = p;
		q = q->next;
	}
	q->next = NULL;
}

3.5 在第i个位置插入一个元素e

//在位置i插入元素e
int InsertLinkedList(LinkedList L, int i, DataType e) {
	int j = 1;
	LinkedList pre, p;
	LinkedList new_node;//带插入的结点
	pre = L;

	cout << "在第"<<i<<"个位置插入元素"<< e << endl;

	//寻找第i个结点,并令pre指向其前驱
	while (pre->next && j < i)
	{
		pre = pre->next;
		j++;
	}
	if (!pre->next || j > i)
	{
		return -1;
	}
	else
	{
		p = pre->next;
		new_node = (LinkedList)malloc(sizeof(LNode));
		new_node->data = e;
		pre->next = new_node;
		new_node->next = p;
		return 1;
	}
}

4  代码实现


#include <iostream>

using namespace std;

//系统中已有此状态码定义,要防止冲突
#ifndef OVERFLOW
#define OVERFLOW    -2  //堆栈上溢
#endif

typedef int DataType;
//单链表结构体
typedef struct LNode
{
	DataType data;
	struct LNode* next;
}LNode;
typedef LNode* LinkedList;	//指向单链表结点的指针


//清理单链表,保留头结点
void ClearLinkedList(LinkedList L) {
	LinkedList pre, p;
	pre = L->next;
	while (pre)
	{
		p = pre->next;
		free(pre);
		pre = p;
	}
	L->next = NULL;
}

//销毁单链表
void DestroyLinkedList(LinkedList* L) {
	LinkedList p = *L;
	while (p)
	{
		p = (*L)->next;
		free(*L);
		(*L) = p;
	}
}
//判断单链表是否为空
bool IsEmpty(LinkedList L) {
	//链表存在且只有头结点
	if (L != NULL && L->next == NULL)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//获取单链表长度
int GetLength(LinkedList L) {
	LinkedList p;
	int lenght = 0;
	cout << "单链表长度:" << endl;
	if (L)
	{
		p = L->next;
		while (p)
		{
			lenght++;
			p = p->next;
		}
	}
	return lenght;
}
//查找第i个位置结点的数据
LinkedList GetElement(LinkedList L, int i) {
	int j = 1;
	DataType e;
	LinkedList p = L->next;
	cout << "返回第" << i << "个位置的元素:" << endl;
	while (p && j<i)
	{
		p = p->next;
		j++;
	}
	if (!p || j>i)
	{
		return NULL;
	}
	else
	{
		return p;
	}
}

void OutPut(LinkedList L) {
	LinkedList p = L->next;
	cout << "链表中的元素:\n" << endl;
	while (p)
	{
		cout << p->data << endl;
		p = p->next;
	}
}

//初始化单链表
void InitLinkedList(LinkedList* L) {
	(*L) = (LinkedList)malloc(sizeof(LNode));
	if (!(*L))
	{
		exit(OVERFLOW);
	}
	(*L)->next = NULL;
}

//头插法
void CreateLinkedList_Head(LinkedList* L,int n) {
	int i;
	LinkedList p;
	DataType tmp;
	*L = (LinkedList)malloc(sizeof(LNode));
	if (!(*L))
	{
		exit(OVERFLOW);
	}
	(*L)->next = NULL;
	cout << "头插法建立单链表:\n" << endl;
	for (int i=1; i<=n; i++)
	{
		p = (LinkedList)malloc(sizeof(LNode));
		cout << "请输入第" << i << "个数:" << endl;
		cin >> tmp;
		p->data = tmp;
		p->next = (*L)->next;
		(*L)->next = p;
	}
}

//尾插法
void CreateLinkedList_Tail(LinkedList* L, int n) {
	int i;
	LinkedList p, q;
	DataType tmp;
	*L = (LinkedList)malloc(sizeof(LNode));
	if (!(*L))
	{
		exit(OVERFLOW);
	}
	(*L)->next = NULL;
	q = *L;
	cout << "尾插法建立单链表:\n" << endl;
	for (int i=1; i<=n; i++)
	{
		p = (LinkedList)malloc(sizeof(LNode));
		cout << "请输入第" << i << "个数:" << endl;
		cin >> tmp;
		p->data = tmp;
		q->next = p;
		q = q->next;
	}
	q->next = NULL;
}

//在位置i插入元素e
int InsertLinkedList(LinkedList L, int i, DataType e) {
	int j = 1;
	LinkedList pre, p;
	LinkedList new_node;//带插入的结点
	pre = L;

	cout << "在第"<<i<<"个位置插入元素"<< e << endl;

	//寻找第i个结点,并令pre指向其前驱
	while (pre->next && j < i)
	{
		pre = pre->next;
		j++;
	}
	if (!pre->next || j > i)
	{
		return -1;
	}
	else
	{
		p = pre->next;
		new_node = (LinkedList)malloc(sizeof(LNode));
		new_node->data = e;
		pre->next = new_node;
		new_node->next = p;
		return 1;
	}
}
//删除第i个位置的结点
int DeleteElement(LinkedList L, int i) {
	int j = 1;
	LinkedList pre, p;
	pre = L;
	cout << "删除第" << i << "个位置的元素" << endl;

	//寻找第i个结点,并令pre指向其前驱
	while (pre->next && j < i)
	{
		pre = pre->next;
		j++;
	}
	if (!pre->next || j > i)
	{
		return -1;
	}
	p = pre->next;
	pre->next = p->next;
	free(p);
	return 1;
}

int main()
{
	LinkedList L;
	InitLinkedList(&L);
	//CreateLinkedList_Head(&L, 5);
	CreateLinkedList_Tail(&L, 5);
	OutPut(L);

	InsertLinkedList(L, 2, 100);
	OutPut(L);
	LinkedList e = GetElement(L, 2);
	cout << "e=" << e->data << endl;
	int len = GetLength(L);
	cout << "len=" << len << endl;
	/*DeleteElement(L, 1);
	OutPut(L);*/
	system("pause");
	return 0;
}

代码简单测试了下尾插法创建单链表,并在第2个位置插入元素100:

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值