顺序表和链表(一)

目录

线性表

一、顺序表

<1>顺序表

(1)静态顺序表

(2)动态顺序表-按需申请

<2>链表

(1)单链表

(2)双链表

主程序(test.c)

头文件(DList.h)

调用函数程序(DList.c)


线性表

++顺序表、链表、栈、队列、字符串++

一、顺序表

连续的物理地址连续(依次)存储数据(数组)

<1>顺序表

(1)静态顺序表
cpp 复制代码
#define N 10
typedef int SLDataType;

struct SeqList
{
	SLDataType a[N];
	SLDataType size;
};

通讯录-C语言-CSDN博客https://blog.csdn.net/Xiaodao12345djs/article/details/142720466?spm=1001.2014.3001.5501这个通讯录就是静态通讯录,缺点很明显,提前开辟内存空间,很可能造成空间浪费

(2)动态顺序表-按需申请

动态顺序表存储数据时会调用函数来开辟动态内存,按需申请,空间利用率较高

cs 复制代码
#define NAME_MAX 10
#define SEX_MAX 5
#define Address_MAX 30
#define NUMBER_MAX 12
#define MAX 100
 
#define DEFAUL_SZ 3
#define INC_SZ 2
 
//联系人信息
typedef struct Message
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char address[Address_MAX];
	char number[NUMBER_MAX];
}Message;
 
//联系人数量(动态)
typedef struct Contact
{
	Message* list;//指向存放人信息空间
	int num;//存放人信息的个数
	int capacity;//当前通信录最大容量
}Contact;

动态通讯录-CSDN博客https://blog.csdn.net/Xiaodao12345djs/article/details/142732433?spm=1001.2014.3001.5501

<2>链表

(1)单链表

++学习链表首先要搞懂结构,物理结构是内存中数据实实在在的变化,为了方便理解,通常用逻辑结构,节点和节点的地址不一定是连续的,所以但单链表的节点中存储下一个节点的地址(指向下一个节点)++

单链表的增删查改-CSDN博客https://blog.csdn.net/Xiaodao12345djs/article/details/143064430?spm=1001.2014.3001.5501

一个数据存一个内存块中,用指针来链接

(2)双链表
主程序(test.c)
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "DList.h"

int main()
{
	//创建哨兵位及初始化
	ListNode* dlist = ListCreate();
	
	// 双向链表尾插
	ListPushBack(dlist, 1);
	ListPushBack(dlist, 2);
	ListPushBack(dlist, 3);
	ListPushBack(dlist, 4);
	ListPushBack(dlist, 5);
	ListPushBack(dlist, 6);
	//打印
	ListPrint(dlist);

	//尾删
	ListPopBack(dlist);
	ListPrint(dlist);
	
	//头插
	ListPushFront(dlist, 1);
	ListPrint(dlist);
	ListPushFront(dlist, 2);
	ListPrint(dlist);
	ListPushFront(dlist, 3);
	ListPrint(dlist);

	//头删
	ListPopFront(dlist);
	ListPopFront(dlist);
	ListPopFront(dlist);
	ListPrint(dlist);

	//查找
	ListNode* pos = ListFind(dlist, 1);
	//在pos前面插入x
	ListInsert(pos, 2);
	ListPrint(dlist);

	//查找
	pos = ListFind(dlist, 2);
	// 双向链表删除pos位置的节点
	ListErase(pos);
	ListPrint(dlist);

	return 0;
}
头文件(DList.h)
cpp 复制代码
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{
	LTDataType _data;
	struct ListNode* _next;
	struct ListNode* _prev;
}ListNode;

// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);
调用函数程序(DList.c)
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#include "DList.h"

//创建新节点及申请空间
ListNode* Buynode(LTDataType x)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	if (node == NULL)
	{
		perror("node:");
	}
	else
	{
		node->_data = x;
		node->_next = NULL;
		node->_prev = NULL;
	}
	return node;
}

//创建哨兵位及初始化
ListNode* ListCreate()
{
	ListNode* newnode = Buynode(0);
	newnode->_next = newnode;
	newnode->_prev = newnode;
	return newnode;
}

// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* newnode = Buynode(x);
	ListNode* tail = pHead->_prev;
	tail->_next = newnode;
	newnode->_prev = tail;
	newnode->_next = pHead;
	pHead->_prev = newnode;
}

// 双向链表打印
void ListPrint(ListNode* pHead)
{
	assert(pHead);

	ListNode* tail = pHead->_next;
	printf("<= phead ");
	while (tail != pHead)
	{
		printf("<=> %d ", tail->_data);
		tail = tail->_next;
	}
	printf("=>\n");
}

// 双向链表尾删
void ListPopBack(ListNode* pHead)
{
	assert(pHead);
	if (pHead->_next == pHead)
	{
		printf("链表为空,无法删除!!!\n");
		return;
	}
	ListNode* tail = pHead->_prev;
	ListNode* prevnode = tail->_prev;
	prevnode->_next = pHead;
	pHead->_prev = prevnode;
	free(tail);
	tail = NULL;
}

// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x)
{
	assert(pHead);

	ListNode* first = pHead->_next;
	ListNode* newnode = Buynode(x);

	newnode->_next = first;
	first->_prev = newnode;
	newnode->_prev = pHead;
	pHead->_next = newnode;
}

// 双向链表头删
void ListPopFront(ListNode* pHead)
{
	assert(pHead);
	if (pHead->_next == pHead)
	{
		printf("链表为空,无法删除!!!\n");
		return;
	}

	ListNode* first = pHead->_next;
	pHead->_next = first->_next;
	first->_next->_prev = pHead;
	free(first);
	first = NULL;

}

// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
	assert(pHead);

	ListNode* scr = pHead->_next;
	while (scr != pHead)
	{
		if (scr->_data == x)
		{
			return scr;
		}
		scr = scr->_next;
	}
	return NULL;
}

// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);
	ListNode* prev = pos->_prev;
	ListNode* newnode = Buynode(x);

	newnode->_next = pos;
	pos->_prev = newnode;
	prev->_next = newnode;
	newnode->_prev = prev;
}

// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{
	assert(pos);

	ListNode* prev = pos->_prev;
	ListNode* next = pos->_next;

	prev->_next = next;
	next->_prev = prev;
	free(pos);
	pos = NULL;
}

双链表的结构体中定义了两个结构体指针,指向上一个节点和下一个节点,更方便增删查改

相关推荐
白榆maple3 分钟前
(蓝桥杯C/C++)——基础算法(上)
c语言·c++·算法·蓝桥杯
search75 分钟前
C 学习(5)
c语言·c++
inputA7 分钟前
【LwIP源码学习4】主线程tcpip_thread
c语言·笔记·单片机·嵌入式硬件·学习
道亦无名12 分钟前
WAPI加密算法
算法
q5673152318 分钟前
Python 中的字符串匹配算法
android·java·javascript·python·算法
C++忠实粉丝1 小时前
Linux系统基础-多线程超详细讲解(5)_单例模式与线程池
linux·运维·服务器·c++·算法·单例模式·职场和发展
2401_877158731 小时前
什么是垃圾回收(Garbage Collection)?
java·开发语言·算法
阿亨仔1 小时前
Pytorch猴痘病识别
人工智能·pytorch·python·深度学习·算法·机器学习
大油头儿1 小时前
Python 实现链表:详解与应用
python·链表
DARLING Zero two♡1 小时前
关于我、重生到500年前凭借C语言改变世界科技vlog.15——深入理解指针(4)
c语言·开发语言·科技