第五周总结01

什么是数据结构

数据结构的起源

  • 1968年,美国高德纳教授,《计算机程序设计艺术》 第一卷《基本算法》出版,开创了数据结构与算法的先河

  • 数据结构是一门研究数据之间关系和操作的学科,而非计算方法

  • 数据结构 + 算法 = 程序 由沃思提出,凭借该论点获得图灵奖,这句话揭示了程序的本质

  • 推荐书籍:程杰《大话数据结构》

数据结构的基本概念

数据:

  • 所有能够输入到计算机中,能被程序处理的,能描述客观事物特征的符号

数据项:

  • 有独立含义数据的最小单位,也叫数据域、域

数据元素:

  • 组成数据的,有一定含义的基本单位,也叫节点、结点、记录

  • 一个数据元素由若干个数据项组成

数据结构:

  • 相互之间存在一种或者多种特定关系的数据元素的集合

算法:

  • 数据结构具备的某些功能,能够解决某种特定问题的方法

数据结构研究的三个方面

  • 数据的逻辑结构

  • 数据的存储结构(物理结构)

  • 数据结构的运算

逻辑结构与存储结构

数据的逻辑结构:

集合:

  • 数据元素同属于一个集体,但是元素之间没有任何关系

线性结构(表):

  • 数据元素之间存在一对一的关系

树型结构(树):

  • 数据元素之间存在一对多的关系

图型结构(图):

  • 数据元素之间存在多对多的关系

数据的物理结构:

*顺序结构:

  • 数据元素存储在连续的内存中,用数据元素的相对位置来表示之间的关系

    • 优点:支持随机访问、访问效率高、适合查找数据

    • 缺点:对内存要求高、空间利用率低,插入和删除很麻烦

*链式结构:

  • 数据元素存储在彼此相互独立的内存空间中,每个独立的数据元素称为节点,每个节点中增加一个数据项用于存储其他节点的地址(指针域),用于表示数据节点之间的关系

    • 优点:对内存要求低、空间利用率高,插入和删除很方便
    • 缺点:不支持随机访问,只能从前到后逐个访问

逻辑结构与物理结构的关系:

  • 表 顺序、链式
  • 树 链式、顺序
  • 图 顺序 + 链式、顺序
  • 每种逻辑结构采用什么存储结构没有明确规定,通常是根据实现的难度以及空间、时间方面的要求,来选择最合适的物理结构

数据结构的运算

​ 建立数据结构 create

​ 销毁数据结构 destroy

​ 清空数据结构 clean

​ 插入元素 insert add

​ 删除元素 delete

​ 访问元素 access

​ 修改元素 modify

​ 查询元素 query

​ 数据结构排序 sort

​ 遍历数据结构 show or print or ergodic

顺序表和链式表的实现

顺序表:

  • 数组

数据项:

  • 存储连续元素的内存首地址
  • 表的容量
  • 元素的数量

运算:

  • 创建、销毁、清空、插入、删除、访问、查询、修改、排序、遍历

    • 注意
      • 1、从始至终保持元素的连续性
      • 2、不能越界
    • 优点:支持随机访问,修改、访问、排序效率高、不容易出现内存碎片
    • 缺点:对内存要求较高,插入、删除元素时不方便、效率低

顺序表举例:

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

#define TYPE int

// 设计顺序表结构
typedef struct Array
{
	TYPE* ptr;	// 存储元素的内存首地址
	size_t cal;	// 表的容量
	size_t cnt; // 元素的数量
}Array;

// 创建
Array* create_array(size_t size)
{
	// 分配表结构内存
	Array* arr = malloc(sizeof(Array));
	// 分配存储元素的内存
	arr->ptr = malloc(sizeof(TYPE)*size);
	// 记录容量
	arr->cal = size;
	// 初始化数量
	arr->cnt = 0;
	return arr;
}

// 销毁
void destroy_array(Array* arr)
{
	free(arr->ptr);
	free(arr);
}

// 清空
void clean_array(Array* arr)
{
	arr->cnt = 0;
}

// 插入
bool insert_array(Array* arr,size_t index,TYPE val)
{
	// 满?
	if(arr->cnt >= arr->cal) return false;
	// 判断下标,为了确保表中元素的连续性
	if(index > arr->cnt) return false;
	/*
	for(int i=arr->cnt; i>index; i--)
	{
		arr->ptr[i] = arr->ptr[i-1];
	}
	*/
	//void *memmove(void *dest, const void *src, size_t n);
	// 后移
	memmove(arr->ptr+index+1,arr->ptr+index,(arr->cnt-index)*sizeof(TYPE));
	arr->ptr[index] = val;
	arr->cnt++;
	return true;
}

// 删除
bool delete_array(Array* arr,size_t index)
{
	if(index >= arr->cnt) return false;
	// 前移
	memmove(arr->ptr+index,arr->ptr+index+1,
		(arr->cnt-index-1)*sizeof(TYPE));
	arr->cnt--;
	return true;
}

// 访问
bool access_array(Array* arr,size_t index,TYPE* val)
{
	if(index >= arr->cnt) return false;
	*val = arr->ptr[index];
	return true;
}
// 修改
bool modify_array(Array* arr,size_t index,TYPE val)
{
	if(index >= arr->cnt) return false;
	arr->ptr[index] = val;
	return true;
}

// 查询
int query_array(Array* arr,TYPE val)
{
	for(int i=0; i<arr->cnt; i++)
	{
		if(val == arr->ptr[i]) return i;
	}
	return -1;
}

// 排序
void sort_array(Array* arr)
{
	for(int i=0; i<arr->cnt-1; i++)
	{
		for(int j=i+1; j<arr->cnt; j++)
		{
			if(arr->ptr[i]>arr->ptr[j])
			{
				TYPE temp = arr->ptr[i];
				arr->ptr[i] = arr->ptr[j];
				arr->ptr[j] = temp;
			}
		}
	}
}

// 遍历
void show_array(Array* arr)
{
	for(int i=0; i<arr->cnt; i++)
	{
		printf("%d ",arr->ptr[i]);
	}
	printf("\n");
}

int main(int argc,const char* argv[])
{
	TYPE val = -10;
	Array* arr = create_array(10);
	for(int i=0; i<5;i++)
	{
		insert_array(arr,0,i);
	}
	
	//show_array(arr);
	//access_array(arr,1,&val);
	//printf("%d\n",val);
	//insert_array(arr,5,88);
	//show_array(arr);
	//delete_array(arr,0);
	//show_array(arr);
	//modify_array(arr,1,5);
	//show_array(arr);
	//printf("%d\n",query_array(arr,4));
	//sort_array(arr);
	//show_array(arr);
}

链式表List:

  • 链表

每个节点Node数据项:

  • 数据域:可以是若干个任意类型的数据项
  • 指针域:指向下一个节点
  • 把若干个节点通过指针域连接在一起就形成了链式表

不带头节点的链式表:

  • 第一个节点的数据域存储的是有效数据的链表

  • 缺点:头插入节点时,会修改指向第一个节点的指针,参数就需要传递二级指针;

  • 删除节点时,需要分两种情况:

    • 1、待删除的是第一个节点时,也会修改指向第一个节点的指针,就需要传递二级指针
    • 2、待删除的不是第一个节点时,就正常删除
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define TYPE int

// 设计单链表的节点
typedef struct Node
{
	TYPE data;// 节点的数据域
	struct Node* next;// 节点的指针域
	
}Node;

// 创建节点
Node* create_node(TYPE data)
{
	// 分配存储节点的内存
	Node* node = malloc(sizeof(Node));
	node->data = data;
	node->next = NULL;
	return node;
}

// 头添加
void add_head_list(Node** head,TYPE data)
{
	Node* node = create_node(data);
	node->next = *head;
	*head = node;
}

// 按值删除
bool delete_value_list(Node** head,TYPE data)
{
	// 如果删除头节点
	if((*head)->data == data)
	{
		Node* temp = *head;
		*head = temp->next;
		free(temp);
		return true;
	}

	for(Node* n=*head; NULL!=n->next; n=n->next)
	{
		if(n->next->data == data)
		{
			// 备份待删除节点
			Node* temp = n->next;
			// 连接待删除节点的前一个和后一个节点
			n->next = temp->next;
			// 删除待删除节点
			free(temp);
			return true;
		}
	}
	return false;
}

// 按位置删除
bool delete_index_list(Node** head,size_t index)
{
	// 如果删除头节点
	if(0 == index)
	{
		Node* temp = *head;
		*head = temp->next;
		free(temp);
		return true;
	}
	
	Node* n = *head;
	while(--index > 0)
	{
		if(NULL == n->next) return false;
		n = n->next;
	}
	if(NULL == n->next) return false;
	// n是待删除节点的前一个

	// 备份待删除节点
	Node* temp = n->next;
	// 连接待删除节点的前一个和后一个节点
	n->next = temp->next;
	// 删除待删除节点
	free(temp);
	return true;
}

//访问
bool access_list(Node* head,size_t index,TYPE* val)
{
	Node* n = head;
	for(int i=0; i<index; i++)
	{
		n = n->next;
		if(NULL == n) return false;
	}
	*val = n->data;
	return true;
}

//遍历
void show_list(Node* head)
{
	for(Node* n=head; NULL!=n; n=n->next)
	{
		printf("%d ",n->data);
	}
	printf("\n");
}

// 排序
void sort_list(Node* head)
{
	for(Node* i=head; NULL!=i->next; i=i->next)
	{
		for(Node* j=i->next; NULL!=j; j=j->next)
		{
			if(i->data > j->data)
			{
				TYPE temp = i->data;
				i->data = j->data;
				j->data = temp;
			}
		}
	}
}

int main(int argc,const char* argv[])
{
	Node* head = NULL;
	for(int i=0;i<10; i++)
	{
		add_head_list(&head,i+10);
	}
	//delete_value_list(&head,19);
	//delete_index_list(&head,9);
	show_list(head);
	TYPE val = -10;
	access_list(head,0,&val);
	printf("%d\n",val);
	sort_list(head);
	show_list(head);
	/*
	Node* n1 = create_node(10);
	Node* n2 = create_node(20);
	Node* n3 = create_node(30);
	Node* n4 = create_node(40);
	Node* n5 = create_node(50);

	n1->next = n2;
	n2->next = n3;
	n3->next = n4;
	n4->next = n5;

	for(Node* n=n1; NULL!=n;n=n->next)
	{
		printf("%d ",n->data);
	}*/
}

带头节点的链式表:

  • 第一个节点的数据域不用于存储有效数据的链表,该头节点是专门用于指向第一个有效数据的节点

  • 优点:无论是否头插入还是头删除,头节点永远不变,变的只是头结点的next,所以不用传递二级指针,也不用额外处理头删除

  • 缺点:额外会多一个头节点

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

#define TYPE int

// 带头节点的链表

// 设计单链表的节点
typedef struct Node
{
	TYPE data;// 节点的数据域
	struct Node* next;// 节点的指针域
	
}Node;

// 创建节点
Node* create_node(TYPE data)
{
	// 分配存储节点的内存
	Node* node = malloc(sizeof(Node));
	// 初始化
	node->data = data;
	node->next = NULL;
	return node;
}

// 头添加
void add_head_list(Node* head,TYPE data)
{
	Node* node = create_node(data);
	node->next = head->next;
	head->next = node;
}

// 尾添加
void add_tail_list(Node* head,TYPE data)
{
	Node* n = head;
	Node* tail = create_node(data);
	while(NULL != n->next) n = n->next;
	n->next = tail;
}

// 按位置删除
bool del_index_list(Node* head,size_t index)
{
	Node* n = head;
	for(int i=0; i<index; i++)
	{
		n = n->next;
		if(NULL == n->next) return false;
	}
	Node* temp = n->next;
	n->next = temp->next;
	free(temp);
	return true;
}

// 按值删除
bool del_value_list(Node* head,TYPE val)
{
	Node* n = head;
	for(Node* i=n; NULL!=n->next; n=n->next)
	{
		if(val == n->next->data)
		{
			Node* temp = n->next;
			n->next = temp->next;
			free(temp);
			return true;
		}
	}
	return false;
}

// 插入
bool insert_list(Node* head,size_t index,TYPE val)
{
	Node* n = head;
	Node* node = create_node(val);
	for(int i=0; i<index; i++)
	{
		n = n->next;
		if(NULL == n->next) return false;
	}
	node->next = n->next;
	n->next = node;
	return true;
}

// 按位置修改
bool modify_index_list(Node* head,size_t index,TYPE val)
{
	Node* n = head->next;
	for(int i=0; i<index; i++)
	{
		n = n->next;
		if(NULL == n) return false;
	}
	n->data = val;
	return true;
}

// 按值修改
bool modify_value_list(Node* head,TYPE old,TYPE val)
{
	for(Node* n=head->next; NULL!=n; n=n->next)
	{
		if(old == n->data)
		{
			n->data = val;
			return true;
		}
	}
	return false;
}

// 访问
bool access_list(Node* head,size_t index,TYPE* val)
{
	Node* n = head->next;
	for(int i=0; i<index; i++)
	{
		if(NULL == n) return false;
		n = n->next;
	}
	if(NULL == n) return false;
	*val = n->data;
	return true;
}

// 查询
int query_list(Node* head,TYPE val)
{
	Node* n = head->next;
	for(int i=0; n; i++,n=n->next)
	{
		if(val == n->data) return i;
	}
	return -1;
}

// 排序
void sort_list(Node* head)
{
	for(Node* i=head->next; NULL!= i->next; i=i->next)
	{
		for(Node* j=i->next; NULL!=j; j=j->next)
		{
			if(i->data < j->data)
			{
				TYPE temp = i->data;
				i->data = j->data;
				j->data = temp;
			}
		}
	}
}

// 遍历
void show_list(Node* head)
{
	for(Node* n=head->next; NULL!=n; n=n->next)
	{
		printf("%d ",n->data);
	}
	printf("\n");
}

int main(int argc,const char* argv[])
{
	// 头节点
	Node* head = create_node(0);
	for(int i=0; i<10; i++)
	{
		//add_head_list(head,i+10);
		add_tail_list(head,i+10);
	}
	//del_index_list(head,5);
	//del_value_list(head,25);
	//insert_list(head,25,5);
	//modify_index_list(head,9,5);
	//modify_value_list(head,98,5);
	/*
	TYPE num = -10;
	access_list(head,5,&num);
	printf("%d\n",num);
	*/
	//printf("%d\n",query_list(head,19));
	sort_list(head);
	for(Node* i=head->next; NULL!=i; i=i->next)
	{
		printf("%d ",i->data);
	}
	//show_list(head);
}

注意:做题时,如果没有说明是否带头节点,那么两种情况都进行考虑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值