Sequential representation and implementation of linear lists, and linked representation and implementation of linear lists - one-way linked lists with head nodes and without nodes

1. Introduction to linear table

1. Linear structure

In a nonempty finite set of data elements:

  • There is only one data element called "first"
  • There is only one data element called "last"
  • Each data element in the set, except the first, has exactly one predecessor
  • Each data element in the set, except the last, has exactly one successor

2. Linear table

​ A linear table is a finite sequence of n data elements. The elements in the same linear table must have the same characteristics, and there is an order-even relationship between the same data elements.

​ The number n (n>=0) of elements in the linear table is defined as the length of the linear table. When 0==n, it is called an empty table. In a non-empty table, each data element has a definite position (subscript ).

​ A linear table is a fairly flexible data structure that can grow or shrink in length as needed.

2. The sequential representation and realization of the linear table:

The sequential representation of the linear table refers to storing the data elements of the linear table sequentially with a group of storage units with continuous addresses.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define TYPE int

// 设计数据结构
typedef struct Array
{
    
    
	TYPE* base;	// 存储元素的基址
	size_t cnt; // 元素的数量
	size_t cap; // 表的容量
}Array;

// 创建线性表,调用者需要提供容量参数,成功返回线性表指针
Array* creat_array(size_t cap)
{
    
    
	// 为线性表创建内存空间
	Array* array = malloc(sizeof(Array));
	// 创建存储元素的内存空间
	array->base = malloc(sizeof(TYPE)*cap);
	// 初始化数量成员
	array->cnt = 0;
	// 备份线性表的容量
	array->cap = cap;
	// 返回线性表指针
	return array;
}

// 销毁线性表,调用者只需要提供线性表指针即可
void destory_array(Array* array)
{
    
    
	// 释放存储元素的内存空间
	free(array->base);
	// 释放线性表内存空间
	free(array);
}

// 清理所有元素
void clear_array(Array* array)
{
    
    
	array->cnt = 0;
}

// 判断线性表是否是空表
bool empty_array(Array* array)
{
    
    
	return 0 == array->cnt;
}

// 求线性表的长度
size_t length_array(Array* array)
{
    
    
	return array->cnt;
}

// 访问指定位置的元素
bool get_array(Array* array,int index,TYPE* elemp)
{
    
    
	if(index >= array->cnt)
		return false;

	*elemp = array->base[index];
	return true;
}

// 在末尾添加元素
void add_back_array(Array* array,TYPE elem)
{
    
    
	// 容量如果不够用
	if(array->cnt >= array->cap)
	{
    
    
		// 容量扩展两倍
		array->cap *= 2;
		// 元素存储空间扩展两倍
		array->base = realloc(array->base,sizeof(TYPE)*array->cap);
	}

	// 末尾添加元素
	array->base[array->cnt++] = elem;
}

// 插入元素
bool insert_array(Array* array,int index,TYPE elem)
{
    
    
	// 如果下标不合法则插入失败
	if(index >= array->cnt)
		return false;

	// 把最后一个元素添加到末尾
	add_back_array(array,array->base[array->cnt-1]);

	// 线性表的顺序存储才可以使用
	memmove(array->base+index+1,array->base+index,sizeof(TYPE)*(array->cnt-index-1));
	
	array->base[index] = elem;
	return true;
}

// 删除元素,按位置删除
bool delete_index_array(Array* array,int index)
{
    
    
	if(index >= array->cnt)
		return false;

	memmove(array->base+index,array->base+index+1,sizeof(TYPE)*(array->cnt-index));
	array->cnt--;
	return true;
}

// 查询元素
int query_array(Array* array,TYPE elem,int (*compare)(const void*,const void*))
{
    
    
	for(int i=array->cnt-1; i>=0; i--)
	{
    
    
		if(!compare(&elem,array->base+i))
			return i;
	}
	return -1;
}

// 删除元素,按值删除
bool delete_value_array(Array* array,TYPE elem,int (*compare)(const void*,const void*))
{
    
    
	return delete_index_array(array,query_array(array,elem,compare));
}

// 对线性表进行排序
void sort_array(Array* array,int (*compare)(const void*,const void*))
{
    
    
	bool flag = true;
	for(int i=array->cnt-1; flag && i>0; i--)
	{
    
    
		flag = false;
		for(int j=0; j<i; j++)
		{
    
    
			if(1 == compare(array->base+j,array->base+j+1))
			{
    
    
				TYPE tmp = array->base[j];
				array->base[j] = array->base[j+1];
				array->base[j+1] = tmp;
				flag = true;
			}
		}
	}
}

// 遍历线性表,只是为了测试
void show_array(Array* array)
{
    
    
	for(int i=0; i<array->cnt; i++)
	{
    
    
		printf("%d ",array->base[i]);
	}
	printf("\n");
}

int main(int argc,const char* argv[])
{
    
    
	Array* array = creat_array(10);
	for(int i=0; i<10; i++)
	{
    
    
		add_back_array(array,rand()%100);
	}
	
	show_array(array);

	int intcmp(const void* p1,const void* p2)
	{
    
    
		if(*(int*)p1 > *(int*)p2)
			return 1;
		if(*(int*)p1 < *(int*)p2)
			return -1;
		return 0;

	}
    
	delete_value_array(array,77,intcmp);

	sort_array(array,intcmp);
	
	show_array(array);
	destory_array(array);
	return 0;
}

**Assignment:** Change the implementation method of the member pointer of the sequential linear table to a flexible array.

3. Chain representation and realization of linear table

​ The characteristic of the sequential storage structure of the linear table is that the two adjacent elements in the logical relationship are also adjacent in the physical position, so any element in the table can be randomly accessed, and its storage location can be used with a simple and intuitive expressed by the formula.

​ This feature also creates a disadvantage of this storage structure: during insertion and deletion operations, a large number of elements need to be moved. Another representation method of the linear table - the chain storage structure just makes up for its shortcomings.

The chain storage structure does not require logically adjacent elements to be physically adjacent, so it does not have the disadvantages of the sequential storage structure, but it also loses the random access advantages of the sequential storage structure.

​ The characteristic of the chain storage structure is that elements can use any position in the storage memory (it can be continuous or discontinuous), and the logical relationship between elements a[i] and a[i+1] does not depend on the relative position, but A data (element pointer) indicating its successor element is added to the element, and the data of the element itself + successor information constitutes a storage image, commonly known as a node (node).

typedef struct Node
{
    
    
    TYPE data;	// 数据域
    struct Node* next;	// 指针域
}Node;

Several element nodes are connected through pointer fields to form a linear list structure called a linked list, referred to as a linked list. There is only one pointer field pointing to subsequent elements in a node. This linked list is also called a one-way linked list.

​ A one-way linked list must have a pointer to the first node, which is called the head pointer, and the node pointed to by it is also called the head node. The head node may not store data, it is simply a placeholder node, and the last The node points to NULL as the end sign.

1. Singly linked list without head node

#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 front_list(Node** head,TYPE data)
{
    
    
	// 创建节点
	Node* node = create_node(data);
	node->next = *head;
	*head = node;
}

// 删除元素
bool delete_index_list(Node** head,int index)
{
    
    
	// 删除第一个节点,因为第一个节点没有前驱
	if(0 == index)
	{
    
    
		Node* node = *head;
		*head = (*head)->next;
		free(node);
		return true;
	}

	// 找到要删除的节点的前驱
	Node* prev = *head;
	while(NULL!=prev->next && index-->1)
			prev = prev->next;

	if(NULL != prev->next)
	{
    
    
		// 备份要删除的节点
		Node* node = prev->next;
		// 前驱节点的指针域指向后继节点
		prev->next = prev->next->next;
		free(node);
		return true;
	}

	return false;
}

// 插入元素
bool insert_list(Node** head,int index,TYPE data)
{
    
    
	Node* node = create_node(data);
	if(0 == index)
	{
    
    
		node->next = *head;
		*head = node;
		return true;
	}

	Node* prev = *head;
	while(NULL!=prev->next && index-->1)
			prev = prev->next;

	if(NULL != prev->next)
	{
    
    
		node->next = prev->next;
		prev->next = node;
		return true;
	}

	return false;
}

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

int main(int argc,const char* argv[])
{
    
    
	// 创建头指针
	Node* head = NULL;
	for(int i=0; i<10; i++)
	{
    
    
		front_list(&head,i);
	}
	show_list(head);
	delete_index_list(&head,9);
	insert_list(&head,9,100);
	show_list(head);
	return 0;
}

2. Singly linked list of leading nodes

​ When performing the insertion and deletion operations of the linked list, the predecessor node and the successor node of the operated node are required. If the operated node is the head node, it has no predecessor node and requires additional special processing. Therefore, in order to facilitate the insertion and deletion operations, it is given A singly linked list adds an empty head node.

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

Node* create_list(void)
{
    
    
	Node* node = malloc(sizeof(Node));
	node->next = NULL;
	return node;
}

void destory_list(Node* head)
{
    
    
	while(head)
	{
    
    
		Node* node = head;
		head = head->next;
		free(node);
	}
}

void front_list(Node* head,TYPE data)
{
    
    
	Node* node = create_node(data);
	node->next = head->next;
	head->next = node;
}

bool delete_index_list(Node* head,int index)
{
    
    
	// 找到要删除的节点的前驱
	Node* prev = head;
	while(NULL != prev->next && index-- >= 1)
		prev = prev->next;

	// index 非法,超出了节点的数量
	if(NULL == prev->next)
		return false;

	// 备份要删除的节点
	Node* node = prev->next;
	// 前驱节点接后继节点
	prev->next = prev->next->next;
	// 删除节点
	free(node);
	return true;
}

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* list = create_list();
	for(int i=0; i<10; i++)
	{
    
    
		front_list(list,i);
	}
	show_list(list);
	delete_index_list(list,3);
	show_list(list);
	return 0;
}

Guess you like

Origin blog.csdn.net/m0_62480610/article/details/126129831