C语言编程数据结构线性表之顺序表和链表原理分析

目录
  • 线性表的定义和特点
    • 线性结构的特点
  • 线性表
  • 顺序存储
    • 顺序表的元素类型定义
    • 顺序表的增删查改
    • 初始化顺序表
    • 扩容顺序表
    • 尾插法增加元素
    • 头插法
    • 任意位置删除
    • 任意位置添加
  • 线性表的链式存储
    • 数据域与指针域
    • 初始化链表
    • 尾插法增加链表结点
    • 头插法添加链表结点
    • 打印链表
    • 任意位置的删除
  • 双向链表
  • 测试双向链表(主函数)
  • 初始化双向链表
  • 头插法插入元素
  • 尾插法插入元素
  • 尾删法删除结点
  • 头删法删除结点
  • doubly-Linked list.c文件
  • doubly-Linkedlist.h

线性表的定义和特点

线性结构的基本特点:除第一个元素无直接前驱,最后一个元素无直接后继,其他元素都有一个前驱和一个后继。

说人话就是:第一个元素不能向前访问,最后一个元素不能向后访问,中间的元素都可以前后访问其他元素。

例如:26个字母表{A,B,C,D,E,F…}就是一个线性表.
虽然该线性表中数据元素各不相同,但每个元素都具有相同的特性,都属于同一数据对象

线性表:由有限个数据特性相同的数据元素构成的有限序列

如果没有数据元素,该线性表也叫空表。

线性结构的特点

1,存在唯一 一个“第一个”与“最后一个”数据元素
2,出第一个和最后一个数据元素,其余元素都有一个前驱和一个后驱
解释一下:前驱和后继就是逻辑关系中的上一个元素和下一个元素
我原先以为是指针之类的。

线性表

线性表的长度可以根据需要增长或减小。还拥有任意位置的插入和删除
线性表分为顺序表和链表

顺序存储

线性表的顺序存储就是顺序表,是指**一组地址连续的存储单元依次存储的数据元素。**实际就是每个元素都是依次储存在地址连续的空间(简称:数组)。对于顺序存储而言,逻辑上是连续的,其物理次序上也是连续的

来看一张图增强一下理解(这是我写顺序存储的习惯,可能会存在差异)

对于线性表的顺序存储的而言,每个数据元素都可以通过下标来快速访问,读取。正规来说就是随机存取

顺序表的元素类型定义

这是我对顺序存储的结构体类型的定义

#define N 8
typedef struct elem
{
	int element;//每个数据元素中的数据项
}sel;
typedef struct seq
{
	sel* arr;//动态开辟的线性表空间的首地址,通过这个指针访问到线性表空间
	int size;//当前已经使用了的空间的个数
	int capacity;//当前的最大的数据元素容量
}sl;

这里我为了简单一些描述,我直接使用了每个数据元素都相当于只有int 类型的数据项。

其实就是跟通讯录一样,每个数据元素都是一个人的全部信息的集合(应该可以这么说吧),而数据项就是每个元素中包含的一部分。

顺序表的增删查改

对于顺序表来说,绝大部分可以当成数组进行操作,当然,也就是要考虑顺序的容量问题,是否需要扩容的几个动态变化问题。

初始化顺序表

void initsequence(sl* a)//初始化动态顺序表
{
	a->size = 0;//数组元素以0开始计算,size是最后一个元素的下标,不是元素总数量
	a->capacity = N;//N在上面已经define了
	a->arr = (sel*)malloc(sizeof(int) * N);
}

扩容顺序表

void checkcapacity(sl* a)//检查是否需要扩容
{
	if (a->size +1== a->capacity)
	{
		a->capacity *= 2;
		a->arr =(sel*) realloc( a->arr,sizeof(int) * (a->capacity));
		if (a->arr == NULL)
		{
			printf("realloc defect");
			exit(-1);
		}
	}
}

扩容是当准备对顺序表的元素进行操作时元素个数已经达到最大容量时,由于我们的size是下标,就要加一。因为我们准备扩容,所以是不会允许size>=capacity。
同时,扩容不能一次性扩太多,否则或导致空间浪费。
又不能扩太少,少了就要多次扩容,会增加消耗。
所以,自己看情况吧。嘻嘻~

尾插法增加元素

void sequpushfront(sl* a,sel* ele)//尾插法
{
	checkcapacity(&a);//检查是否需要扩容
	*(a->arr + a->size) =ele->element;//因为我只设置了一个int类型的如果数据元素中有多个数据项向下看
	++(a->size);
}
void sequpushfront(sl* a,sel* ele)//尾插法
{
	checkcapacity(&a);//检查是否需要扩容
	(a->arr + a->size)->n =ele->element;//假设是有多个数据项就这样依次匹配(a->arr + a->size)已经访问到每个元素的地址再->n访问到相应元素的空间进行存储。
	++(a->size);
}

尾插法没那么复杂,检查一下扩容,直接在后面放入元素就行。
下面我就不再举例了,举一反三很容易的。

头插法

void sequpushback(sl* a, int n)//头插法
{
	checkcapacity(&a);//检查是否需要扩容
	int head = 0;
	int end = a->size;
	while (end>=head)
	{
		*(a->arr + end + 1) = *(a->arr + end);

		--end;
	}
	++(a->size);
	*(a->arr + head) = n;
}

头插法就需要将放入位置后的元素全部向后移动一个位置。
但是,怎么移又是要考虑一下的问题。

是从前向后开始移动,还是从最后一个元素开始移动。

如果是从前向后移动

会造成这个样子,后面元素就一直是1,则,这种方法就是错误的。

再来看看从后向前移动

这种方法是可以行的通的。
先扩容
再元素向后移,再头插。

void sequpushback(sl* a, sel* ele)//头插法
{
	checkcapacity(&a);//检查是否需要扩容
	int head = 0;
	int end = a->size;
	while (end>=head)
	{
		*(a->arr + end + 1) = *(a->arr + end);

		--end;
	}
	++(a->size);
	*(a->arr + head) = ele->element;
}

任意位置删除

删除就不头删尾删了,直接任意位置删除。

找到那个元素的下标,再开始向前覆盖
对于删除而言,元素移动又是一个麻烦事。
这次我们对于删除而言,元素得从前向后开始移动。

void sequpopmid(sl* a, int n)//中间删除,n是要删除的位置
{
	assert(n>=0&&n<=a->size);
	for (int i = n ; i < a->size-1; i++)
	{
		*(a->arr + i) = *(a->arr + i + 1);
	}
	--(a->size);
}

删除后要将边界也就是size自减,防止越界。

任意位置添加

传要添加的位置,再开始向后移动。

void sequpushmid(sl* a, int n,sel* ele)//中间添加
{
	assert(n>=0&&n=<a->size+1);//要在有效位置添加
	checkcapacity(&a);//检查是否需要扩容
	int head = n;
	int end = a->size;
	while (end>=head)
	{
		*(a->arr + end + 1) = *(a->arr + end);
		--end;
	}
	++(a->size);
	*(a->arr + head) = ele->element;
}

其实就是头插法的一种变形。

小总结

对于数组删除元素,要从前向后开始移动。
而对于数组增加元素,要从后向前开始移动。
同时删除添加的位置都要符合条件,不能越界。

线性表的链式存储

该存储结构的存储特点是:用一组任意的存储单元存储线性表的数据元素。(这组存储单元可以是连续的也可以是不连续的,简称:随机分布的存储单元)

数据域与指针域

而每个分配到存储单元都要分为两个部分:数据域与指针域。
这两个域或者信息组成数据元素的存储映像。是逻辑层次的元素在物理层次的投影。也叫结点。

  • 数据域:储存每个数据元素,包括各个数据项
  • 指针域:储存一个指针,也就是下一个结点的地址

注意,链式储存也就是链表,其每个结点的地址都是随机的,并不是像顺序表一样,每个空间依次排列。

链表有超多种结构,如:单链表,单向/双向循环链表,双向链表,二叉链表,十字链表,邻链表,邻接多重表等。

本文主要分析单链表,循环链表,双向链表。其余的暂时不分析(其实是我不会,目前比较菜),以后会补充分析。

数据结构最好先画图,这样可以增强理解与分析。

大致了解一下链表的结构。

由于链表中的每个结点的物理关系是不确定的,是随机的,就需要靠指针域来表示,构成逻辑关系。指针指向是十分重要的。

这个哨兵位的头节点的可要可不要的。

#include "linkedlist.h"
void test()
{
	list* head;
	list* last;
	initLinkedlist(&head,&last);
	pushlast(&last, 1);//尾插法
	pushlast(&last, 2);
	pushlast(&last, 3);
	pushlast(&last, 4);
	pushfront(&head, 5);//头插法
	pushfront(&head, 8);//头插法
	pushfront(&head, 7);//头插法
	pushfront(&head, 6);//头插法
	popchoice(&head, 0);//任意位置删除
	//poshposition(&head, 3);//任意位置插入
	printlist(&head);//打印
}
int main(void)
{
	test();
	return 0;
}

先分析哨兵位的链表,好理解

初始化链表

void initLinkedlist(list** head,list** last)//初始化链表
{
	*head = (list*)malloc(sizeof(list));
	(*head)->next = NULL;
	*last=*head;
}

head就是哨兵位,而这个last,是要来定位最后一个结点,当last指向head时,就代表是一个空表。
由于我是在测试函数中创建了哨兵结点和尾结点指针,所以要对指针进行操作得传一个二级指针,传址调用才能才能对链表进行影响。
当尾结点指向哨兵结点时,表示是一个空表。

尾插法增加链表结点

void pushlast(list** last, int num)//尾插法
{
	list* new = (list*)malloc(sizeof(list));
	new->n = num;
	new->next = (*last)->next;
	(*last)->next = new;
	(*last) = new;
}

要在尾结点,也就是last结点。

尾插结点图解,就是这样的。
同时,当last->next的指向newnode后,last也要再移向newnode,因为newnode变成了尾结点,下次插入会在这次newnode的后面进行插入。

头插法添加链表结点

void pushfront(list** head, int num)//头插法
{
	list* new = (list*)malloc(sizeof(list));
	new->n = num;
	new->next = (*head)->next;
	(*head)->next = new;
}

要在哨兵位后进行插入,每次插入都要满足在哨兵位节点后进行。

而哨兵位结点是始终不变的,我们可以通过这样的操作不断头插。

打印链表

void printlist(list** head)//打印
{
	list* p = (*head)->next;
	while (p)
	{
		printf("%d ", p->n);
		p = p->next;
	}
}

从哨兵位结点进行遍历,依次打印。

任意位置的删除

void popchoice(list** head, int pos)//任意位置删除
{
	assert(pos<8&pos>=0);
	int i = 0;
	list* pre = *head;
	list* cur = (*head)->next;
	while (i < pos)
	{
		pre = cur;
		cur = cur->next;
		i++;
	}
	pre->next = cur->next;
	free(cur);
}

由于是有哨兵位的链表,在任意位置删除还好,但无哨兵位的链表,就有一些麻烦。

虽然差不多的变化。因位要保存结点的前一个结点地址,当没有哨兵位的时候就需要if判断一下。其实也没多麻烦。
任意位置插入和删除是一样的。

双向链表

这是另一种链式结构。
每个结点都具有两个指针,一个指向上一个逻辑关系结点,一个指向下一个逻辑关系结点。

这一般使用一个哨兵位的结点,可以创建使用双向链表的步骤更简单。
对于双向链表与单链表而言,双向链表在链表的插入,删除以及多个操作上更具有优势。

如:尾插。
对于单链表,要指针遍历找到尾结点,再插入。时间复杂度为O(N).
而双向链表,他的头结点的prev指针指向了最后一个结点,根本不需要依次遍历。

像一些插入操作
如:前插
单链表都要准备两个指针。
而双向链表直接访问prev指针就可以找到上一个结点。

虽然,指针较多可能比单链表麻烦,但整体操作上,却要简单。

而且,在以后的很多结构上,单链表都不会拿出来单独使用,而是作为某个数据结构的一部分。双向链表才是会作为一个主体来使用。

测试双向链表(主函数)

#include "doubly_Linkedlist.h"
void doublelinkedlist1()
{
	doulink head;
	initlinkedlist(&head);//初始化双向链表
	LinkedlistFrontPush(&head, 1);//头插法
	LinkedlistFrontPush(&head, 2);//头插法
	LinkedlistFrontPush(&head, 3);//头插法
	LinkedlistFrontPush(&head, 4);//头插法
	LinkedlistFrontPush(&head, 5);//头插法
	LinkedlistBackpush(&head, 6);//尾插法
	LinkedlistBackpush(&head, 7);//尾插法
	LinkedlistBackpush(&head, 8);//尾插法
	LinkedlistBackpush(&head, 9);//尾插法
	LinkedlistBackpush(&head, 10);//尾插法
	LinkedlistFrontPop(&head);//头删
	LinkedlistFrontPop(&head);//头删
	LinkedlistFrontPop(&head);//头删
	LinkedlistBackPop(&head);//尾删
	LinkedlistBackPop(&head);//尾删
	LinkedlistBackPop(&head);//尾删
	LinkedlistBackPop(&head);//尾删
	LinkedlistBackPop(&head);//尾删
	LinkedlistPrint(&head);//打印链表
}
int main(void)
{
	doublelinkedlist1();
}

因为我是创建了一个结构体变量,要对其进行操作,需要传址调用,如果传值调用会,导致实际上哨兵并未改变,只是改变了函数中的形参。

初始化双向链表

void initlinkedlist(doulink* head)//初始化双向链表
{
	(*head).next = head;
	(*head).prev = head;
}

因为双向链表要形成一个闭环,初始化时也要形成闭环

头插法插入元素

void LinkedlistFrontPush(doulink* head, lint n)//头插法
{
	doulink* newnode = (doulink*)malloc(sizeof(doulink));
	newnode->num = n;
	doulink*phead=(*head).next;//原头节点
	newnode->next = phead;//新的后驱指针接入下一个
	(*head).next = newnode;//将哨兵链接新结点
	newnode->prev = head;//新结点的前驱指针指向哨兵
	phead->prev = newnode;//原头结点的前驱指针指向新的头节点
}

尾插法插入元素

void LinkedlistBackpush(doulink* head, lint n)//尾插法
{
	doulink* newnode = (doulink*)malloc(sizeof(doulink));
	newnode->num = n;
	doulink* plast = (*head).prev;//找到尾结点
	newnode->prev = plast;//新的尾接入原尾结点
	newnode->next = plast->next;//新接入哨兵
	plast->next = newnode;//原尾结点next指向新的尾
	(*head).prev = newnode;//头节点的prev指向新的尾结点,形成闭环
}

有链表中多个结点的情况

尾删法删除结点

void LinkedlistBackPop(doulink* head)//尾删
{
	doulink* last = (*head).prev;//找到要删除的尾结点
	doulink* llast = last->prev;//找到删除后的新的尾结点
	if (last == head)
	{
		printf("Empty List\n");
		return;
	}
	(*head).prev = llast;//改变哨兵结点prev指向
	llast->next = last->next;//让新的尾结点的next接入哨兵
	free(last);//删除内存
}

头删法删除结点

void LinkedlistFrontPop(doulink* head)//头删
{
	doulink* phead = (*head).next;
	doulink* second = phead->next;
	if (phead == head)
	{
		printf("Empty List\n");
		return;
	}
	second->prev = phead->prev;
	(*head).next = second;
	free(first);
}

对于头插尾插,尾删头删,一定要注意顺序,不然可能会导致指针指向错误的地方。

而对于双向链表的删除插入,不需要多个指针,这样要方便很多。

以下是代码的全部主体

doubly-Linked list.c文件

#include "doubly_Linkedlist.h"
void initlinkedlist(doulink* head)//初始化双向链表
{
	(*head).next = head;
	(*head).prev = head;
}
void LinkedlistFrontPush(doulink* head, lint n)//头插法
{
	doulink* newnode = (doulink*)malloc(sizeof(doulink));
	newnode->num = n;
	doulink*phead=(*head).next;//原头节点
	newnode->next = phead;//新的后驱指针接入下一个
	(*head).next = newnode;//将哨兵链接新结点
	newnode->prev = head;//新结点的前驱指针指向哨兵
	phead->prev = newnode;//原头结点的前驱指针指向新的头节点
}
void LinkedlistBackpush(doulink* head, lint n)//尾插法
{
	doulink* newnode = (doulink*)malloc(sizeof(doulink));
	newnode->num = n;
	doulink* plast = (*head).prev;//找到尾结点
	newnode->prev = plast;//新的尾接入原尾结点
	newnode->next = plast->next;//新接入哨兵
	plast->next = newnode;//原尾结点next指向新的尾
	(*head).prev = newnode;//头节点的prev指向新的尾结点,形成闭环
}
void LinkedlistFrontPop(doulink* head)//头删
{
	doulink* phead = (*head).next;
	doulink* second = phead->next;
	if (phead == head)
	{
		printf("Empty List\n");
		return;
	}
	second->prev = phead->prev;
	(*head).next = second;
}
void LinkedlistBackPop(doulink* head)//尾删
{
	doulink* last = (*head).prev;//找到要删除的尾结点
	doulink* llast = last->prev;//找到删除后的新的尾结点
	if (last == head)
	{
		printf("Empty List\n");
		return;
	}
	(*head).prev = llast;//改变哨兵结点prev指向
	llast->next = last->next;//让新的尾结点的next接入哨兵
	free(last);
}
void LinkedlistPrint(doulink* head)//打印链表
{
	doulink* cur = (*head).next;
	while (cur != head)
	{
		printf("%d ", cur->num);
		cur = cur->next;
	}
}

doubly-Linkedlist.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int lint;
typedef struct doulinked
{
	lint num;
	lint* prev;
	lint* next;
}doulink;
void initlinkedlist(doulink* head);//初始化双向链表
void LinkedlistFrontPush(doulink* head, lint n);//头插法
void LinkedlistBackpush(doulink* head, lint n);//尾插法
void LinkedlistFrontPop(doulink* head);//头删
void LinkedlistBackPop(doulink* head);//尾删
void LinkedlistPrint(doulink* head);//打印链表

以上就是C语言编程数据结构线性表之顺序表和链表原理分析的详细内容,更多关于C语言数据结构线性表顺序表和链表的资料请关注我们其它相关文章!

感谢阅读~

(0)

相关推荐

  • C语言线性表的顺序表示与实现实例详解

    1.概述 通常来说顺序表是在计算机的内存中以数组的形式保存的线性表,是用一组地址连续的存储单元依次存储数据元素的线性数据结构.线性表采用顺序存储的方式存储就称之为顺序表.顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中. 将表中元素一个接一个的存入一组连续的存储单元中,这种存储结构就是顺序结构. 采用顺序存储结构的线性表简称为" 顺序表".顺序表的存储特点是:只要确定了起始位置,表中任一元素的地址都通过下列公式得到:LOC(ai)=LOC(a1)+(i-1)*L 1≤

  • c语言实现顺序表的基本操作

    数据结构顺序表操作 复制代码 代码如下: #include <stdio.h>#include <stdlib.h>#include <malloc.h>#define LIST_INIT_SIZE 100#define LISINCREMENT 10#define ElemType int#define Status inttypedef struct Sq{ ElemType *elem; int length; int listsize;}SqList;Statu

  • C语言创建和操作单链表数据结构的实例教程

    1,为什么要用到链表 数组作为存放同类数据的集合,给我们在程序设计时带来很多的方便,增加了灵活性.但数组也同样存在一些弊病.如数组的大小在定义时要事先规定,不能在程序中进行调整,这样一来,在程序设计中针对不同问题有时需要3 0个大小的数组,有时需要5 0个数组的大小,难于统一.我们只能够根据可能的最大需求来定义数组,常常会造成一定存储空间的浪费. 我们希望构造动态的数组,随时可以调整数组的大小,以满足不同问题的需要.链表就是我们需要的动态数组.它是在程序的执行过程中根据需要有数据存储就向系统要求

  • C语言 数据结构之链表实现代码

    前言 最近在复习数据结构的相关知识,感觉在初学的时候还是有很多东西没有掌握,不过现在终于算是搞得比较有头绪了,所以就在写出来和大家一起分享! 什么是链表 简单的说,链表就是由多个结点离散分配,彼此通过指针相连,每个结点只有一个前驱结点和后继结点.首节点无前驱结点,为结点无后继结点的一种存储结构. 链表的结构 头结点:链表的第一个有效结点前面的结点,头结点并不存放有效数据,也就是数据域为空,加头结点的主要目的是为了方便链表的操作. 首节点:链表的第一个有效结点,结点包含数据域和指针域. 尾结点:尾

  • C语言编程数据结构线性表之顺序表和链表原理分析

    目录 线性表的定义和特点 线性结构的特点 线性表 顺序存储 顺序表的元素类型定义 顺序表的增删查改 初始化顺序表 扩容顺序表 尾插法增加元素 头插法 任意位置删除 任意位置添加 线性表的链式存储 数据域与指针域 初始化链表 尾插法增加链表结点 头插法添加链表结点 打印链表 任意位置的删除 双向链表 测试双向链表(主函数) 初始化双向链表 头插法插入元素 尾插法插入元素 尾删法删除结点 头删法删除结点 doubly-Linked list.c文件 doubly-Linkedlist.h 线性表的定

  • C语言线性表中顺序表超详细理解

    目录 一.本章重点 二.线性表 三.顺序表 四.静态顺序表接口实现 4.1顺序表初始化 4.2顺序表打印 4.3顺序表尾插 4.4顺序表尾删 4.5顺序表头插 4.6顺序表头删 4.7顺序表任意位置插入 4.8顺序表任意位置删除 五.动态顺序表接口实现 5.1顺序表的初始化 5.2顺序表打印 5.3顺序表尾插 5.4顺序表尾删 5.5顺序表头插 5.6顺序表头删 5.7顺序表任意位置插入 5.8顺序表任意位置删除 六.在线0j练习 一.移除元素(力扣) 二.合并两个有序数组(力扣) 一.本章重点

  • C++ 数据结构超详细讲解顺序表

    目录 前言 一.顺序表是什么 概念及结构 二.顺序表的实现 顺序表的缺点 几道练手题 总结 (●’◡’●) 前言 线性表是n个具有相同特性的数据元素的有限序列.线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表.链表.栈.队列.字符串. 线性表在逻辑上是线性结构,也就是说连续的一条直线,但是在物理结构并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储. 本章我们来深度初体验顺序表 一.顺序表是什么 概念及结构 顺序表是一段物理地址连续的存储单元依次存储数据元素的线性

  • C语言编程数据结构的栈和队列

    目录 栈 数组实现 标题全部代码 Stack_array.c Stack_array.h 初始化数组栈 满栈后扩容 是否为空栈 压栈和退栈 链表实现 stack_chain.h stack_chain.c 整个压栈流程 整个弹栈流程 出栈情况 队列 队列的实现 queue_chain.h queue_chain.c 一个结构体类型用于维护这个队列 概念流程图 入队列的实现 出队列的实现 是否空队 栈 栈是一种以后进先出为顺序对对象进行添加或删除的数据结构 对栈进行形象记忆就像是桌子上的一堆书或一

  • 语言编程花絮内建构建顺序示例详解

    目录 1 构建 顺序 1.1 交叉编译 1.2 设置 2 构建测试支持 1 构建 顺序 依据词法名顺序 当导入一个包,且这个包 定义了 init(), 那么导入时init()将被执行. 具体执行顺序: 全局变量定义时的函数 import 执行导入 -> cont 执行常量 --> var 执行变量 --> 执行初始化 init() --> 执行 main() ----> main import pk1 ---> pk1 const ... import pk2 ---&

  • C语言编程深入理解取整取余取模问题示例分析

    目录 1. 取整问题 1.0向取整(C语言默认的取整方案) 2.地板取整(向负无穷的方向取整) 3.天花板取整(向+无穷的方向取整) 4.四舍五入取整 汇总例子 2.取模问题  1.余数的定义 2.两种余数 3.为什么会有这种现象? 3.区分取余与取模 1.取余与与取模的本质区别 2.理解链 3.同符号与不同符号 1.同符号: 2.不同符号 1. 取整问题 1.0向取整(C语言默认的取整方案) #include<stdio.h> #include<windows.h> int ma

  • C语言的线性表之顺序表你了解吗

    目录 线性表 —— 顺序表 (C语言) 1. 顺序表的储存结构 2. 顺序表的基本操作 2.1 顺序表的插入 2.2 顺序表的查找 2.3 顺序表的删除 总结 线性表 —— 顺序表 (C语言) 概念 线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表中的数据元素,这种表示也称做线性表的顺序储存结构或顺序映像.通常,称这种存储结构的线性表为顺序表 (Sequential List) .其特点是,逻辑上相邻的数据元素,其物理次序也是相邻的. 1. 顺序表的储存结构 #include <st

  • C语言编程数据结构栈与队列的全面讲解示例教程

    目录 一.栈的表示和实现 1栈的概念和结构 2栈的初始化 3压栈(栈顶插入一个数据) 4出栈(栈顶删除一个数据) 5取栈顶元素 6取栈顶元素 7判断栈是否为空 二.队列的表示和实现 1队列的概念及结构 2队列的实现 3队列初始化 4入队(队尾插入一个数据) 5出队(队头删除一个数据) 6取队头数据 7取队尾数据 8计算队列中数据个数 9判断队列是否为空 10销毁队列 总结 一.栈的表示和实现 1栈的概念和结构 栈:一种特殊的线性表(逻辑上数据是连着放的),其只允许在固定的一端进行插入和删除操作.

  • C语言编程数据结构带头双向循环链表全面详解

    目录 前言 一.什么是带头循环双向链表 二.链表初始化 三.链表接口函数 1.尾插 2.头插 3.头删 4.尾删 5.任意位置插入数据 6.任意位置删除数据 四.打印链表 总结 前言 上一篇数据结构专栏:C语言数据结构单链表接口函数全面讲解教程 我们介绍了单链表的各个接口函数,大家可能会发现单链表存在一些缺陷:比如它一个节点要存储数据+下一个节点地址,占用的空间要远多于顺序表:并且由于单链表是无法从后往前找的,如果你想进行尾删这样的操作,你必须从第一个节点往后找,你的时间复杂度一定是O(n).

  • C语言编程数据结构基础详解小白篇

    目录 数据结构的基本信息 数据结构 逻辑结构 1,集合结构 2,线性结构 3,树结构 4,图结构或网结构 存储结构 顺序储存结构 链式储存结构 抽象数据类型 介绍 数据结构的基本信息 数据:是客观事物的符号表示,是所有能输入到计算机中并被计算机程序处理的符号的总称.如:字符串,实数整数.... 数据元素:是数据的基本单位,在计算机中通常被作为一个整体进行考虑与处理.如组成通讯录的每一个人的信息,数据元素可以完整的描述一个对象. 数据项:是组成数据元素的,具有独立意义的,不可分割的最小单位(也就是

随机推荐