数据结构-单链表

本文详细介绍了线性表的单链表数据结构,包括基本概念、单链表的特点以及部分算法分析。通过头插法和尾插法创建单链表,并展示了节点的插入和删除操作。此外,还提供了线性表的链式表示和实现的C++代码示例,包括全局头文件、链表结构定义和相关操作函数。
摘要由CSDN通过智能技术生成

目录

基本概念

 单链表的特点

 部分算法分析

 线性表的链式表示和实现

global.h

 LinkList.h

 LinkListTest.cpp

运行结果


​​​​​​​

基本概念

  • 线性表最常用且简单的一种数据结构,一个线性表是n个元素的有限序列
  • 线性结构:在数据元素的非空有限集合中,有以下几种特点
存在唯一的一个被称作"第一个的元素"
存在唯一的一个被称作"最后一个的元素"
除第一个以外,集合中的每一个数据元素均只有一个前驱
除最后一个以外,集合中的每一个数据元素均只有一个后继

 单链表的特点

  •  用任意的存储单元存储数据元素
  • 存储单元可以是连续的,也可以是不连续的
  • 每个存储单元除了存储其本身数据以外,还需存储器直接后继的存储位置
  • 便于数据的插入与删除操作

 部分算法分析

  • 头插法创建单链表
    //初始化单链表(头插法),创建n个链表节点长度的单链表
    Status InitLinkListHead(LinkList& L, int n) {
    	cout << "为" << n << "个节点赋值:" << endl;
    	//创建头结点,此时头指针的地址为头结点地址
    	L = (LinkList)malloc(sizeof(LNode));
    	//判断结构体指针是否为NULL,即空间是否分配成功
    	if (!L)
    		return ERROR;
    	//将头结点的next指针只想NULL
    	L->next = NULL;
    	//创建n个链表节点
    	LinkList p;
    	for (int i = n; i > 0; --i) {
    		//分配新的节点,并给节点赋值
    		p = (LinkList)malloc(sizeof(LNode));
    		if (!p)
    			return ERROR;
    		cin >> p->data;
    		p->next = L->next;
    		L->next = p;
    	}
    	cout << "头插法链表创建成功" << endl;
    	return OK;
    }

    头插法节点的插入位置始终在头结点之后插入新节点,所以当创建节点时输入 34、21、56,遍历单链表时输出为逆序即 56、21、34

  •  尾插法创建单链表
//初始化单链表(尾插法)
Status InitLinkListTail(LinkList& L, int n) {
	cout << "为" << n << "个节点赋值:" << endl;
	LinkList p,rear;
	L = (LinkList)malloc(sizeof(LNode));
	if (!L)
		return ERROR;
	rear = L;
	for (int i = 0; i < n; ++i) {
		p = (LinkList)malloc(sizeof(LNode));
		if (!p)
			return ERROR;
		cin >> p->data;
		//使上一个节点指向新节点
		rear->next = p;
		//使rear指针始终指向最末尾的一个节点
		rear = p;
	}
	rear->next = NULL;
	cout << "尾插法创建单链表成功" << endl;
	return OK;
}

 尾插法始终在rear指针(始终指向单链表的最后的一个节点)后添加新的节点,使用尾插法创建单链表时输入 34、21、56,在遍历单链表时输出为正序即 34、21、56

  •  单链表节点的插入操作
//单链表节点的插入操作:在第i个位置插入节点
Status InsertLinkList(LinkList& L, int i, ElemType elem) {
	//此时p为头结点
	LinkList p = L;
	int j = 0;
	//找到插入位置节点的前一个节点
	while (p && j < i - 1) {
		p = p->next;
		++j;
	}
	//判断该节点是否存在
	if (!p || j > i)
		return ERROR;
	//创建新节点
	LinkList node = (LinkList)malloc(sizeof(LNode));
	if (!node)
		return ERROR;
	node->data = elem;
	node->next = p->next;
	p->next = node;
	return OK;
}

找到插入位置的前一个节点,即节点p,让node指向p的下一个节点,再让p指向新节点node即可


 线性表的链式表示和实现

  • global.h 
  • LinkList.h
  • LinkListTest.h

global.h

相关头文件的引用,以及相应全局变量、常量的声明

#pragma once

#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<windows.h>

using namespace std;

#define TRUE 1

#define FALSE 0

#define OK 1

#define ERROR 0

#define INFEASIBLE -1

#define EQ(a,b) ((a) == (b))

#define LT(a,b) ((a) < (b))

#define LQ(a,b) ((a) <= (b))

#define MT(a,b) ((a) > (b))

#define MQ(a,b) ((a) >= (b))

typedef int Status;

 LinkList.h

单链表结构的定义,以及单链表的相关操作算法

#pragma once
#include"global.h"

#define ElemType int
/*
* 线性表的链式表示
*/

/*----------线性表的但单链表存储结构----------*/
typedef struct LNode {
	//数据域
	ElemType data;    
	//指针域
	struct LNode* next;
}LNode,*LinkList;

//初始化单链表(头插法),创建n个链表节点长度的单链表
Status InitLinkListHead(LinkList& L, int n) {
	cout << "为" << n << "个节点赋值:" << endl;
	//创建头结点,此时头指针的地址为头结点地址
	L = (LinkList)malloc(sizeof(LNode));
	//判断结构体指针是否为NULL,即空间是否分配成功
	if (!L)
		return ERROR;
	//将头结点的next指针只想NULL
	L->next = NULL;
	//创建n个链表节点
	LinkList p;
	for (int i = n; i > 0; --i) {
		//分配新的节点,并给节点赋值
		p = (LinkList)malloc(sizeof(LNode));
		if (!p)
			return ERROR;
		cin >> p->data;
		p->next = L->next;
		L->next = p;
	}
	cout << "头插法链表创建成功" << endl;
	return OK;
}

//初始化单链表(尾插法)
Status InitLinkListTail(LinkList& L, int n) {
	cout << "为" << n << "个节点赋值:" << endl;
	LinkList p,rear;
	L = (LinkList)malloc(sizeof(LNode));
	if (!L)
		return ERROR;
	rear = L;
	for (int i = 0; i < n; ++i) {
		p = (LinkList)malloc(sizeof(LNode));
		if (!p)
			return ERROR;
		cin >> p->data;
		//使上一个节点指向新节点
		rear->next = p;
		//使rear指针始终指向最末尾的一个节点
		rear = p;
	}
	rear->next = NULL;
	cout << "尾插法创建单链表成功" << endl;
	return OK;
}

//单链表的遍历,输出单链表内的所有节点数据
void ShowLinkList(LinkList L) {
	//L->next指的是头结点后的一个节点,头节点不存储数据
	LinkList p = L->next;
	if (!p) {
		cout << "单链表内的数据为空" << endl;
	}
	cout << "单链表内的节点数据:";
	while (p) {
		cout << p->data << " ";
		//指向下一个节点
		p = p->next;
	}
	cout << endl;
}

//获取单链表内的第i个节点数据
Status GetLinkListElem(LinkList L, int i, ElemType& elem) {
	LinkList p;
	p = L->next;
	int j = 1;
	//找到第i个节点
	while (p && j < i) {
		p = p->next;
		++j;
	}
	//判断第i个节点是否存在
	if (!p || j > i)
		return ERROR;
	elem = p->data;
	return OK;
}

//单链表节点的插入操作:在第i个位置插入节点
Status InsertLinkList(LinkList& L, int i, ElemType elem) {
	//此时p为头结点
	LinkList p = L;
	int j = 0;
	//找到插入位置节点的前一个节点
	while (p && j < i - 1) {
		p = p->next;
		++j;
	}
	//判断该节点是否存在
	if (!p || j > i)
		return ERROR;
	//创建新节点
	LinkList node = (LinkList)malloc(sizeof(LNode));
	if (!node)
		return ERROR;
	node->data = elem;
	node->next = p->next;
	p->next = node;
	return OK;
}

//单链表节点的删除操作:删除第i个节点
Status DeleteLinkList(LinkList& L, int i) {
	LinkList p = L;
	int j = 0;
	while (p && j < i - 1) {
		p = p->next;
		++j;
	}
	if (!p || j > i - 1)
		return ERROR;
	//q为第i个节点,即所要删除的节点
	LinkList q = p->next;
	if (!q)
		return ERROR;
	//让p指向q的下一个节点
	p->next = q->next;
	//释放该节点的空间
	free(q);
	return OK;
}

//对单链表进行升序操作(并未交换节点之间的指向,仅仅交换了节点之间的数据)
Status LinkListIsAscending(LinkList& L) {
	LinkList p = L->next;
	while (p) {
		LinkList r = p->next;
		while (r) {
			if (p->data > r->data) {
				ElemType elem = r->data;
				r->data = p->data;
				p->data = elem;
			}
			r = r->next;
		}
		p = p->next;
	}
	return OK;
}

//将两个有序的单链表合并为一个有序的单链表
Status MergeLinkList(LinkList& Lc, LinkList& La, LinkList& Lb) {
	LinkList pa = La->next;
	LinkList pb = Lb->next;
	//使用La的头结点作为Lc的头结点
	LinkList pc = Lc = La;
	while (pa && pb) {
		//比较pa与pb节点内的数据大小,将小的节点插入Lc链表内
		if (pa->data <= pb->data) {
			pc->next = pa;
			pc = pa;
			pa = pa->next;
		}
		else {
			pc->next = pb;
			pc = pb;
			pb = pb->next;
		}
	}
	//将pa或pb剩余的节点插入Lc节点(前提:La与Lb均是有序链表)
	pc->next = pa ? pa : pb;
	if (!Lb)
		return ERROR;
	free(Lb);
	return OK;
}

 LinkListTest.cpp

#include"LinkList.h"

int main() {
	LinkList list;
	int n;
	cout << "(头插法)输入创建单链表的节点数:" << endl;
	cin >> n;
	InitLinkListHead(list,n);
	ShowLinkList(list);
	LinkList list2;
	cout << "(尾插法)输入创建单链表的节点数:" << endl;
	cin >> n;
	InitLinkListTail(list2, n);
	ShowLinkList(list2);
	cout << "单链表的节点插入操作:" << endl;
	cout << "输入插入节点的位置:" << endl;
	cin >> n;
	ElemType elem;
	cout << "输入插入节点的数据:" << endl;
	cin >> elem;
	InsertLinkList(list, n, elem);
	ShowLinkList(list);
	cout << "单链表节点删除操作:" << endl;
	cout << "请输入删除节点的位置:" << endl;
	cin >> n;
	DeleteLinkList(list2, n);
	ShowLinkList(list2);
	cout << "单链表的合并操作:" << endl;
	LinkListIsAscending(list);
	ShowLinkList(list);
	LinkListIsAscending(list2);
	ShowLinkList(list2);
	LinkList Lc;
	MergeLinkList(Lc, list, list2);
	ShowLinkList(Lc);
}

运行结果

(头插法)输入创建单链表的节点数:
4
为4个节点赋值:
10 5 34 76
头插法链表创建成功
单链表内的节点数据:76 34 5 10
(尾插法)输入创建单链表的节点数:
6
为6个节点赋值:
12 3 6 85 34 89
尾插法创建单链表成功
单链表内的节点数据:12 3 6 85 34 89
单链表的节点插入操作:
输入插入节点的位置:
3
输入插入节点的数据:
21
单链表内的节点数据:76 34 21 5 10
单链表节点删除操作:
请输入删除节点的位置:
2
单链表内的节点数据:12 6 85 34 89
单链表的合并操作:
单链表内的节点数据:5 10 21 34 76
单链表内的节点数据:6 12 34 85 89
单链表内的节点数据:5 6 10 12 21 34 34 76 85 89

F:\DataStructureForC++\Project\Debug\Project1.exe (process 2244) exited with code 0.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值