sizeof和strlen、线性表

目录

1、sizeof和strlen

2、线性表

3、单链表

4、循环单链表

5、双链表

6、循环双链表

7、静态链表


1、sizeof和strlen

char sArr[] = "ILOVEC";
/*用strlen()求长度*/
printf("sArr的长度=%d\n", strlen(sArr));

很显然,上面示例代码的运行结果为 6(因为不包括结束字符 \0)。

char sArr[] = "ILOVEC";
/*用sizeof求长度*/
printf("sArr的长度=%d\n", sizeof(sArr));

相对于函数 strlen,这里的示例代码运行结果为 7(因为它包括结束字符 \0)。同时,对 sizeof 而言,因为缓冲区已经用已知字符串进行了初始化,其长度是固定的,所以 sizeof 在编译时计算缓冲区的长度。也正是由于在编译时计算,因此 sizeof 不能用来返回动态分配的内存空间的大小。

2、线性表

定义:由n(n>=0)个相同类型的元素组成的有序集合。

线性表中元素个数n,称为线性表的长度。当n=0时,为空表。

a1是唯一的“第一个”数据元素,an是唯一的“最后一个”数据元素。

ai-1为ai的直接前驱,ai+1为ai的直接后继。

特点:

表中元素的个数是有限的。

表中元素的数据类型都相同。意味着每一个元素占用相同大小的空间。

表中元素具有逻辑上的顺序性,在序列中各元素排序有其先后顺序。

插入操作:
最好情况:在表尾插入元素,不需要移动元素,时间复杂度为O(1)。

最坏情况:在表头插入元素,所有元素依次后移,时间复杂度为O(n)。

平均情况:在插入位置概率均等的情况下,平均移动元素的次数为n/2,时间复杂度为O(n)。(计算时间度的时候忽略最高项的系数,所以不是O(n/2))

动态分配的数组也属于顺序储存结构

#include <stdio.h>
#include <stdlib.h>

#define maxsize 50
typedef int elemtype;//顺序表中元素的类型
//静态分配
typedef struct {
	elemtype data[maxsize];//定义的数组,用来存元素
	int length;//当前顺序表中有多少个元素
}sqlist;

int main()
{
	sqlist L;//顺序表的名称
	bool ret;//查看返回值,布尔型是true或者false
	elemtype del;//用来储存要删除的元素
	//首先手动在顺序表中赋值
	L.data[0] = 1;
	L.data[1] = 2;
	L.data[2] = 3;
	L.length = 3;//总计三个元素

	return 0;
}

#include <stdio.h>
#include <stdlib.h>

#define maxsize 50
typedef int elemtype;//顺序表中元素的类型

//静态分配
typedef struct {
	elemtype data[maxsize];//定义的数组,用来存元素
	int length;//当前顺序表中有多少个元素
}sqlist;
//参数加不加引用,看是否需要改变主函数中的对应的变量值
bool list_insert(sqlist& L, int i, elemtype e);
void list_print(sqlist& L);
bool list_delete(sqlist& L, int i, elemtype& e);
int elem_locate(sqlist L, elemtype e);

int main()
{
	int elem_pos=0;

	sqlist L;//顺序表的名称
	bool ret;//查看返回值,布尔型是true或者false
	elemtype del;//用来储存要删除的元素
	//首先手动在顺序表中赋值
	L.data[0] = 1;
	L.data[1] = 2;
	L.data[2] = 3;
	L.length = 3;//总计三个元素
	ret = list_insert(L, 2, 60);//往第二个位置插入60
	if (ret) { printf("插入成功\n"); list_print(L); }
	else printf("插入失败\n");

	ret=list_delete(L, 1, del);
	if (ret) { printf("删除成功\n"); printf("删除的元素值为%d\n", del); list_print(L); }
	else printf("删除失败\n");

	elem_pos = elem_locate(L, 3);
	if (elem_pos) { printf("查找成功\n"); printf("元素位置为%d\n", elem_pos); }
	else printf("查找失败\n");

	return 0;
}

int elem_locate(sqlist L, elemtype e)
{
	int i;
	for (i = 0; i < L.length; i++)
	{
		if (L.data[i] == e) { return (i + 1); }
	}
	return 0;
}
bool list_delete(sqlist& L, int i, elemtype& e)
{
	if (i<1 || i>L.length)return false;
	if (L.length == 0)return false;
	e = L.data[i - 1];
	for (int j = i; j < L.length; j++)L.data[j - 1] = L.data[j];
	L.length--;
}
void list_print(sqlist& L)
{
	for (int i = 0; i < L.length; i++)printf("%4d", L.data[i]);//遍历数组
	printf("\n");//要求打印到一排,就需要最后再加\n
}
bool list_insert(sqlist& L, int i, elemtype e)//i代表插入的位置,从1开始,e代表要插入的元素
{
	if (i<1 || i>L.length + 1)return false;//i小于1或者i大于表的长度则不合法
	if (L.length >= maxsize)return false;//表的长度大于数组的最大值,不合法
	for (int j = L.length; j >= i; j--)L.data[j] = L.data[j - 1];//表长大于要插入的位置的话,后面的元素依次后移
	L.data[i - 1] = e;//(除了插入第一个位置)经过上面for循环的后移之后,将元素插入
	L.length++;//表长加一
	return true;//插入成功,返回true
}

3、单链表

头结点:链表中第一个结点的存储位置,用来标识单链表。

头结点:在单链表第一个结点之前附加的一个结点,为了操作上的方便。

若链表有头结点,则头指针永远指向头结点,不论链表是否为空,头指针均不为空,头指针是链表的必须元素,他标识一个链表。

头结点是为了操作的方便而设立的,其数据域一般为空,或者存放链表的长度。有头结点后,对在第一结点前插入和删除第一结点的操作就统一了,不需要频繁重置头指针。但头结点不是必须的。

p->next:整体是访问结构体空间的一个成员(next成员)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

typedef int elemtype;
typedef struct LNode {
	elemtype data;
	struct LNode* next;//存放下一个结点
} LNode, * LinkList;

LinkList list_creat_head(LinkList& L);
void list_print(LinkList L);
LinkList list_creat_tail(LinkList& L);
LNode* elem_get(LinkList L, int i);
LinkList elem_locate(LinkList L, elemtype e);
bool list_insert_front(LinkList L, int i, elemtype e);
bool list_delete(LinkList L, int i);

int main()
{
	LinkList L;//链表头,是结构体指针类型
	LinkList search;//用来存储拿到的某一个结点
	//list_creat_head(L);//输入数据可以是3 4 5 6 9999//9999用来结束输入
	list_creat_tail(L);
	list_print(L);//链表打印
	//查找链表第二个位置的元素值
	search = elem_get(L, 2);
	if (search != NULL)
	{
		printf("按序号查找成功\n");
		printf("%d\n", search->data);
	}
	//*****************************************
	//按值查询
	search = elem_locate(L, 6);
	if (search != NULL)
	{
		printf("按值查找成功\n");
		printf("%d\n", search->data);
	}
	//*****************************************
	list_insert_front(L, 2, 99);//新结点插入第i个位置
	list_print(L);
	list_delete(L, 4);//删除第4个结点
	list_print(L);
	return 0;
}

//删除第i个位置插入元素
bool list_delete(LinkList L, int i)
{
	LinkList p = elem_get(L, i - 1);//查找删除位置的前驱结点
	if (NULL == p)return false;//要删除的位置不存在
	LinkList q = p->next;
	p->next = q->next;
	free(q);
	q = NULL;//为了避免野指针
	return true;
}

//往第i个位置插入元素
bool list_insert_front(LinkList L, int i, elemtype e)
{
	LinkList p = elem_get(L, i - 1);//拿到要插入位置的前一个位置
	if (NULL == p)return false;
	LinkList s = (LinkList)malloc(sizeof(LNode));//给新结点申请空间
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}
//按值查找结点
LinkList elem_locate(LinkList L, elemtype e)
{
	LinkList p = L->next;
	while (p != NULL && p->data != e) { p = p->next; }
	return p;
}
//按序号查找结点值
LNode* elem_get(LinkList L, int i)
{
	int j = 1;
	LNode* p = L->next;
	if (i == 0)return L;
	if (i < 1)return NULL;
	while (p && j < i) { p = p->next; j++; }
	return p;
}
//尾插法新建链表
LinkList list_creat_tail(LinkList& L)
{
	int x;
	L = (LinkList)malloc(sizeof(LNode));//带头结点的链表
	LNode* s, * r = L;//或者LinkList s,r=L;r代表链表表尾结点,指向链表尾部
	//3 4 5 6 7 9999
	scanf("%d", &x);
	while (x != 9999)
	{
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		r->next = s;
		r = s;//r指向新的表尾结点
		scanf("%d", &x);
	}
	r->next = NULL;
	return L;
}
//打印链表中每个结点的值
void list_print(LinkList L)//没有引用,所以此时给L赋值不会使原来的链表发生改变
{
	L = L->next;
	while (L != NULL)
	{
		printf("%3d", L->data);
		L = L->next;//依次移动
	}
	printf("\n"); 
}
//头插法新建链表
LinkList list_creat_head(LinkList& L)
{
	LNode* s; int x;
	L = (LinkList)malloc(sizeof(LNode));//带头结点的链表
	L->next = NULL;
	scanf("%d", &x);//从标准输入中读取数据
	//3 4 5 6 7 9999
	while (x != 9999)
	{
		s = (LNode*)malloc(sizeof(LNode));//申请一个新空间给s
		s->data = x;//把读到的值,给新空间中的data成员
		s->next = L->next;//
		L->next = s;
		scanf("%d", &x);
	}
	return L;//因为用了引用,所以不返回也可以
}

4、循环单链表

循环单链表与单链表的区别在于,表中最后一个结点的next指针不是NULL,而是指向头结点L,从而整个链表形成一个环。

5、双链表

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;
typedef struct DNode {
	ElemType data;
	struct DNode* prior, * next;//前驱,后继
}DNode,*DLinkList;

DLinkList DList_insert_head(DLinkList& DL);
void DList_Print(DLinkList DL);
DLinkList DList_insert_tail(DLinkList& DL);
bool DList_insert_front(DLinkList DL, int i, ElemType e);
DNode* Elem_Get(DLinkList DL, int i);
bool DList_Delete(DLinkList DL, int i);

int main()
{
	DLinkList DL;
	DLinkList search;
	DList_insert_head(DL);//头部插入
	DList_Print(DL);

	return 0;
}

//删除第i个结点
bool DList_Delete(DLinkList DL, int i)
{
	DLinkList p = Elem_Get(DL, i - 1);
	if (NULL == p)return false;
	DLinkList q;
	q = p->next;
	if (q == NULL)return false;//删除的元素不存在
	p->next = q->next;
	if (q->next != NULL)q->next->prior = p;
	free(q);
	return true;
}
//按序号查找结点值
DNode* Elem_Get(DLinkList DL, int i)
{
	int j = 1;
	DNode* p = DL->next;
	if (i == 0)return DL;
	if (i < 0)return NULL;
	while (p&&j<i)
	{
		p = p->next;
		j++;
	}
	return p;
}
//新结点插入第i个位置
bool DList_insert_front(DLinkList DL, int i, ElemType e)
{
	DLinkList p = Elem_Get(DL, i - 1);//找到前一个位置的地址
	if (NULL == p) { return false; }
	DLinkList s = (DLinkList)malloc(sizeof(DNode));
	s->data = e;
	s->next = p->next;
	p->next->prior = s;
	s->prior = p;
	p->next = s;
	return true;
}
//双向链表尾插法
DLinkList DList_insert_tail(DLinkList& DL)
{
	int x;
	DL = (DLinkList)malloc(sizeof(DNode));
	DNode* s, * r = DL;//r代表尾指针
	DL->prior = NULL;
	//3 4 5 9 9999
	scanf("%d", &x);
	while (x != 9999)
	{
		s = (DNode*)malloc(sizeof(DNode));
		s->data = x;
		r->next = s;
		s->prior = r;
		r = s;//r指向新的表尾结点
		scanf("%d", &x);
	}
	r->next = NULL;//尾结点的next指针赋值为NULL
	return DL;
}
//链表打印
void DList_Print(DLinkList DL)
{
	DL = DL->next;
	while (DL!=NULL)
	{
		printf("%3d", DL->data);
		DL = DL->next;
	}
	printf("\n");
}
//双向链表头插法
DLinkList DList_insert_head(DLinkList& DL)
{
	DNode* s; int x;
	DL = (DLinkList)malloc(sizeof(DNode));//带头结点的链表
	DL->next = NULL;
	DL->prior = NULL;
	scanf("%d",&x);//从标准输入读取数据
	//3 4 5 6 7 9999
	while (x!=9999)
	{
		s = (DLinkList)malloc(sizeof(DNode));
		s->data = x;
		s->next = DL->next;
		if (DL->next != NULL) { DL->next->prior = s; }
		s->prior = DL;
		DL->next = s;
		scanf("%d", &x);
	}
	return DL;
}

6、循环双链表

循环双链表与双链表的区别在于,表中最后一个结点的next指针不是NULL,而是指向头结点L,同时L->prior指向尾结点。当循环双链表为空时,其头结点prior域都等于L。

7、静态链表

静态链表是借助数组来描述线性表的链式存储结构。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值