04ds_02day

04ds_02day

============================
2022-8-2
============================

note

malloc calloc realloc 开辟空间
free 释放空间
malloc(sizeof(int) * 4);

线性存储结构
    顺序表
        数组
            一维数组
            多维数组
    链表
        是一种物理存储单元上非连续\非顺序的存储结构
        链表是由一个一个的结点组成的
        每一个结点是由两部分组成 : 数据域 和 指针域
        数据域 : 是用来存储结点的数据的
        指针域 : 是用来存储下一个结点的地址的

        在操作链表时包括有 : 增 删 改 查一系列的操作

        在描述链表时会用到一些属性
            有头链表/无头链表	有没有头结点的意思
            循环链表/不循环链表	链表是否可以构成环
            单向链表/双向链表	遍历链表方向

        有头单向不循环的链表
--------------------------------------------------------------------------------
    创建一个有头单向不循环的链表
    1.创建头结点		llist_create();
    2.插入数据结点		llist_insert();
        先把新创建出的结点挂到链表上,再改变链表之前的结构
        头插法{11,22,33,44,55}
        把数据结点插入到头结点之后的位置
        头结点->NULL
        头结点->11->NULL
        头结点->22->11->NULL
        头结点->33->22->11->NULL
        
        尾插法{11,22,33,44,55}
        把数据结点插入到链表最后的位置
        头结点->NULL
        头结点->11->NULL
        头结点->11->22->NULL
        头结点->11->22->33->NULL
    3.遍历链表			llist_display();
    4.销毁链表			llist_destroy();
        销毁链表或者删除结点时要注意
        单链表再删除时需要一前一后两个指针
    =======================================
    5.查找结点			llist_find();
    6.删除结点			llist_delete();
    7.拿出结点			llist_fetch();

==============================
作业
1.把今天讲过的内容完完整整的复习一遍
2.把有头单向不循环链表再重新的写一遍
3.尝试自己搞定有头单向循环链表
==============================

链表

llist.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#ifndef __LLIST_H
#define __LLIST_H

enum MODE {HEADINSERT, TAILINSERT};//头插法和尾插法

#define NAMESIZE 20

typedef struct llist_node
{
	int id;//数据域中的数据
	char name[NAMESIZE];//数据域中的数据
	int math;//数据域中的数据
	struct llist_node *next;//指针域(指向下一个结点的指针)
}LLIST;

LLIST *llist_create();//创建头结点

int llist_insert(LLIST *,const void *,int);//插入数据结点

void llist_display(LLIST *);//遍历链表

void llist_destroy(LLIST *);//销毁链表

LLIST *llist_find(LLIST *, const void *);//查找结点

int llist_delete(LLIST *, const void *);//删除结点

int llist_fetch(LLIST *, const void *, void *);//取出数据

#endif

llist.c

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "llist.h"

LLIST *llist_create()
{
	LLIST *handler = NULL;//指向头结点的指针

	handler = malloc(sizeof(LLIST));//为头结点开辟空间
	if(handler == NULL)//判断是否开辟空间失败
		return NULL;//开辟空间失败,函数结束,并且返回NULL
	handler->next = NULL;//让头结点的next指针指向NULL
	return handler;//返回头结点的地址
}

int llist_insert(LLIST *handler,const void *data,int mode)
{
	LLIST *p = handler;//通过指针p代替handler做操作
	LLIST *newnode = NULL;//指向新创建出来的数据结点

	newnode = malloc(sizeof(LLIST));//开辟数据结点的空间
	if(newnode == NULL)//判断开辟空间是否失败
		return -1;//开辟失败,结束函数,并且返回-1
	
	memcpy(newnode, data, sizeof(LLIST));
	//把数据拷贝到数据结点中
	switch(mode)
	{
		case HEADINSERT : newnode->next = p->next; break;
		case TAILINSERT : while(p->next != NULL) p = p->next;
							break;
		default : free(newnode); return -2;
		//模式选择有误,释放空间,结束程序,并且返回-2
	}
	p->next = newnode;
	return 0;
}

void llist_display(LLIST *handler)
{
	LLIST *cur = NULL;//指向每一个数据结点

	for(cur = handler->next; cur != NULL; cur = cur->next)
		printf("%d	%s	%d\n", cur->id,cur->name,cur->math);
}

void llist_destroy(LLIST *handler)
{
	LLIST *back = handler;//指向头结点的指针
	LLIST *cur = handler->next;//指向第一个数据结点

	while(cur != NULL)
	{
		back->next = cur->next;//把要释放的结点从链表中拆除
		free(cur);//释放数据结点
		cur = back->next;
	}
	free(back);//释放头结点
}

LLIST *llist_find(LLIST *handler, const void *find_data)
{
	LLIST *cur = NULL;//循环查找的指针

	for(cur = handler->next; cur != NULL; cur = cur->next)
	{
		if(cur->id == *(int *)find_data || 
			!strcmp(cur->name, find_data))
		{
			return cur;//找到要查找的结点,并且返回
		}
	}
	return NULL;//没有找到数据结点,返回NULL
}

int llist_delete(LLIST *handler, const void *find_data)
{
	LLIST *back = handler;//指向要删除的结点的前一个位置
	LLIST *cur = NULL;//指向要删除的结点

	cur = llist_find(handler, find_data);//查找结点
	if(cur == NULL)//判断是否没有找到结点
		return -1;

	while(back->next != cur)//找到要删除结点的前一个位置
		back = back->next;

	back->next = cur->next;//把要删除结点从链表中拆除
	free(cur);//释放删除的结点
	return 0;
}

int llist_fetch(LLIST *handler, const void *find_data, void *save)
{
	LLIST *back = handler;
	LLIST *cur = NULL;

	cur = llist_find(handler, find_data);
	if(cur == NULL)
		return -1;
	
	while(back->next != cur)
		back = back->next;
	
	back->next = cur->next;
	memcpy(save, cur, sizeof(LLIST));
	free(cur);
	return 0;
}

main.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <stdio.h>
#include "llist.h"

int main(void)
{
	LLIST *handler = NULL;//handler指针指向头结点
	LLIST *find = NULL;//find指针指向将来找到的结点
	LLIST data;//用来存储数据的变量
	LLIST save;//将来保存取出的数据
	int i = 0;//循环变量
	int ret = 0;//用来接收返回值的变量
	int find_id = 100;//要查找的id号
	char *find_name = "stu4";//要查找的名字

	handler = llist_create();//创建头结点
	if(handler == NULL)//判断创建头结点是否失败
		return -1;//创建头结点失败,结束程序,并且返回-1
	
	for(i = 0; i < 5; i++)//循环进行插入数据结点
	{
		data.id = 100 + i;//存储数据
		sprintf(data.name, "stu%d", i);//存储数据
		data.math = 100 - i;//存储数据
		data.next = NULL;//让next指针指向空
		llist_insert(handler, &data, TAILINSERT);
		//插入数据结点
	}
	
	llist_display(handler);//遍历链表

	printf("====================\n");
/*
	find = llist_find(handler, "stu9");//查找结点
	if(find == NULL)//判断是否没有找到结点
		printf("Not Find It!\n");
	else
		printf("Find It!	%d	%s	%d\n", find->id, find->name, find->math);
*/
#if 0
	ret = llist_delete(handler, "stu9");//删除结点
	if(ret != 0)//判断是否删除失败
		printf("Delete It Is Failed!\n");
	else
		printf("Delete It!\n");
#else
	ret = llist_fetch(handler,"stu9",&save);//取出数据
	if(ret != 0)
		printf("Fetch It Is Failed!\n");
	else
		printf("Fetch It!	%d	%s	%d\n",save.id, save.name, save.math);
#endif
	printf("====================\n");

	llist_display(handler);//遍历链表

	llist_destroy(handler);//销毁链表

	return 0;
}

makefile

1
2
3
4
llist : main.o llist.o
	gcc -o $@ $^
clean :
	rm -rf *.o llist