链表
可变数组
应具备的特点:
1、根据需求自动变大
2、知道它目前的大小
3、可以精确访问其中的元素
编写函数实现
将结构体Array当作一个数组使用
上代码
Array array_create(int init_size)//-->初始化结构(数组)
void array_free(Array *a)// -->释放数组所占的空间
int array_size(const Array*a)//-->数组的长度
int* array_at(Array*a,int index)//-->定位数组中的某个元素
void array_inflate(Array*a,int more_size)//-->自动增加数组容量
#include<stdio.h>
#include<stdlib.h>
typedef struct{
int*array;
int size;
}Array;
Array array_create(int init_size);//init_size为所传入数组的大小
//另一种方法:
//Array array_create(Array*a,int init_size)//传入一个Array类型的指针,直接对一个结构操作。
//{
//a->size = init_size;
//a->array = (int*)malloc(a->size*sizeof(int));
// } //这样的结构有风险:1、当传入的指针为NULL时 2、这个1指针可能曾经指向一个结构。要先用free()释放掉。
void array_free(Array *a);
int array_size(const Array*a);
int* array_at(Array*a,int index);
void array_inflate(Array*a,int more_size);//创建一个新的空间(类似于array_create),来装原来装不下的数据,并释放掉原来的旧空间。
int main()
{
int longth;
scanf("%d",&longth);
Array a=array_create(longth);
array_free(&a);
printf("%d",array_size);
}
Array array_create(int init_size)
{
Array a;
a.size = init_size;
a.array= (int*)malloc(a.size*sizeof(int));
return a;//存在于array_create中,可以在主函数中声明一个Array类型的结构体初始化为array_create的返回值,以此完成创造结构体的目的。
}
void array_free(Array *a)//传入定义好的结构,释放掉它所申请的内存
{
free(a->array);
a->size = 0;
a->array = NULL;//防止第二次调用时程序崩溃,free一个空指针是无害的
}
int array_size(const Array*a);//查看a数组的大小 (封装)
{
return a->size;
}
int* array_at(Array*a,int index)
{
return (a->array)+index;//或者&(a->array[index])
}
void array_inflate(Array*a,int more_size)
{
int *p = (int*)malloc(sizeof(int)*(a->size+more_size));
for(i = 0;i<a->size;i++)
{
p[i] = a->array[i];
}
free(a->array);
a->array = p;
a->size+=more_size;//更新这个数组,使之容纳更大的数据。
}
可变数组的缺陷
1.每次都要新申请一块内存,然后再释放旧的内存,但此时系统的剩余内存可能不足以容纳新申请的内存(即使总内存足够)
2、每次更新都要复制原来的数据,花费时间多
解决方法:每次申请一块block大小的内存,并用指针指向这块内存,连接它们
所以链表代替它
//链表
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int value;
struct Note*next;
}node;
int main()
{
node *head = NULL;
int number;
do{
scanf("%d",&number);
if(number != 1)
{
//添加链表
node *p = (node*)malloc(sizeof(node));//每次malloc出的地址不一样
p->value = number;
p->next = NULL;
//找到最后一个
node *last = head;
if(last != 0)
{
while(last->next != 0)
last = last->next;
//接近元素
last->next = p;
}
else
head = p;
}
}while(number != -1);
return 0;
}
链表中的每个结点实质是一个结构体,包含数据部分和指向下一个节点的指针。
链表的增删改查、头插法、尾插法
/链表
//链表的创建
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct Note{
char name[20];
struct Note*next;
}note;
note* create()//创建链表
{
note *head,*current,*next;
char str[10];
char flag;
printf("Please enter the name:");
scanf("%s",str);
getchar();//得到scanf时留在缓冲区的空格
head = (note*)malloc(sizeof(note));
strcpy(head->name,str);
current = head;
printf("continue?");
scanf("%c",&flag);
while(flag == 'Y')
{
scanf("%s",str);
getchar();
next =(note*)malloc(sizeof(note));
strcpy(next->name,str);
next->next = NULL;
current->next = next;//链接两个结点
//上一个元素的指针指向下一个元素
current = next;//移动current,让他指向next(类比于指针的++p)
printf("continue?");
scanf("%c",&flag);
}
return head;//返回的是链表的首地址
}
void list(note*p)//遍历链表并打印内容
{
while(1)
{
printf("%s\n",p->name);
if(p->next != NULL)
{
p = p->next;
}
else
break;
}
}
void insert(int position,note**p)//链表的插入函数//传入指针的地址来修改指针所指//当修改结构里的指针时,传入指向这结构体的指针
{
note *head,*backward;
backward = *p;
char str[10];
printf("Please enter a insert name: ");
scanf("%s",str);
getchar();
head = (note*)malloc(sizeof(note));
strcpy(head->name,str);
if(position)
{
for(int i =1;i<position;i++)
{
backward = backward->next;
}
head->next = backward->next;//插入元素指向后一个元素
backward->next = head;//上一个指向插入元素
}
else
{
*p = head;
head->next = backward;
}
}
void link_delete(int position,note**p)
{
note *backward;
backward = *p;
if(position)
{
for(int i = 1;i<=position;i++)
backward = backward->next;
*p = backward->next;
free((*p)->next);
}
else
{
*p = (*p)->next;
free(backward);
}
}
int main()
{
note*p = create();
insert(0,&p);
link_delete(0,&p);
list(p);
return 0;
}
链表的插入
新建一个元素,让指定插入位置的前一个元素指向要插入的元素
再让要插入的元素指向它的后一个元素
具体操作:让前一个元素的指针指向待插入元素,再让待插入元素指向后一个元素
头插法
把后建立的结点插在头部。用这种方法建立起来的链表的实际顺序与输入顺序刚好向反,输出时为倒序!
s->Data=x; //数据域插入的值
s->Next=L->Next;
L->Next=s;
第一个结点的指针域,等于头指针的指针域等于NULL,表示链尾。然后将节点插入到链表中,这两步的顺序一定不能相反。
//
代码如下
LinkList CreateList_Head(LinkList L)
{
LinkList s;int x;
L = (LNode*)malloc(sizeof(LNode)); //创建头结点
L->Next=NULL;
scanf("%d",&x);
while(x!=9999){
s=(LNode*)malloc(sizeof(LNode));
s->Data=x;
s->Next=L->Next; //在第二次循环时将第二个数据插到刚开始的两个数据之间
L->Next=s; //插入结点
scanf("%d",&x);
}
return L;
}
有关的好的文章
C语言数据结构之链表的增删改查——wrlovesmile