顺序表和链表(一)

目录

线性表

一、顺序表

<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;
}

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

相关推荐
时光の尘4 分钟前
C语言菜鸟入门·关键字·void的用法
c语言·开发语言·c++·算法·c#·c·关键字
蚂蚁没问题s5 分钟前
图像处理 - 色彩空间转换
图像处理·人工智能·算法·机器学习·计算机视觉
小林熬夜学编程9 分钟前
【Linux系统编程】第四十九弹---日志系统构建指南:从基础结构到时间处理与Log类实现
linux·运维·服务器·c语言·开发语言·c++
戊子仲秋17 分钟前
【LeetCode】每日一题 2024_11_21 矩阵中的蛇(模拟)
算法·leetcode·矩阵
HP-Patience21 分钟前
【机器学习】- 模型复杂度vs模型误差
python·算法·机器学习
折枝寄北25 分钟前
C指针之舞——指针探秘之旅(2)
c语言·开发语言
螺旋天光极锐斩空闪壹式!30 分钟前
第十三课 二维数组(2)方向数组
开发语言·c++·算法
peter801533 分钟前
算法项目推荐
算法
小小白白蛆34 分钟前
剑指offer JZ51 数组中的逆序对
数据结构·算法·排序算法
十五年专注C++开发40 分钟前
C++不完整类型(Incomplete Type)的检测与避免
开发语言·c++·算法·设计模式