升级版(推荐)
- 为了解决前面传统方法(顺序存储)中插入和删除需要移动大量的元素,因为耗费时间,所以采用链式存储来解决问题:让所有的元素都不相邻,不连续,可以在内存中的任意位置。只找到当前节点和下一个节点的位置即可,这样就可以直接插入而不移动元素。
- 节点(node):包含:数据域,指针域。指针域中存储的信息为指针或链。由n个节点链接成应该表–>线性表。
- 我们把链表中第一个节点(头节点)存储的位置叫做头指针。
- 在单链表前设一个头节点,不存储任何个人私有数据信息,但存储一些公共信息:线性表的长度等等。
头节点和头指针的区别
头指针
- 头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针。
- 头指针具有标识作用,所以常用头指针冠以链表的名字。
- 无论链表是否为空,头指针均不为空。头指针是链表的必要元素。
头节点
- 头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域一般无意义(也可存放链表的长度)。
- 有了头结点,对在第一元素结点前插入结点和删除第一结点,其操作与其它结点的操作就统一了。
- 头结点不定是链表必须要素
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/cfe3a11f7587e4a389a3e4ac4b093528.png)
插入
s->next = p->next;
p->next = s;
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/90884d2af55327f3b398acd562d3633e.png)
- 表头和表尾的情况:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/7ab4187e0b27ea6c8327e7a5f60ca96d.png)
删除
list* temp = p->next;
p->next = temp->next;
mystruct* data = &temp->data;
free(temp);
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/1205bdc9cc92ba2b9f4f1384ba4e3d08.png)
创建n个元素的链表
头插法
typedef struct List
{
Data data;
List* next;
}list;
void(list* old,Data data_)
{
......
list* l = (list*)malloc(sizeof(list));
l->next = NULL;
list* input = (list*)malloc(sizeof(list));
input->data = data;
input->next = l->next;
l->next = input;
old = l;
}
尾插法
void(list* old,Data data_)
{
list* behind = NULL;
old = (list*)malloc(sizeof(list));
behind = old;
list* input = (list*)malloc(sizeof(list));
list->data = data_;
behind->next = input;
behind = input;
behind->next = NULL;
}
实例(歌曲管理):
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<stdlib.h>
typedef struct Node
{
Node* next;
}node;
typedef struct Common_list
{
node head;
int length;
}common_list;
common_list* creat_list()
{
common_list*temp_creat;
temp_creat = (common_list*)malloc(sizeof(common_list));
if (temp_creat == nullptr)
{
printf("空间开辟错误!!!\n");
return nullptr;
}
printf("已成功创建空列表!!1\n");
temp_creat->head.next = nullptr;
temp_creat->length = 0;
printf("空列表初始化成功!!1\n");
return temp_creat;
}
void insert_list(common_list**old,node*input, int pos)
{
common_list*temp_insert = *old;
if (temp_insert == nullptr)
{
printf("传入空间错误!!!\n\n");
return ;
}
else if (pos<0)
{
printf("位置号不能小于0");
return;
}
else if (pos > temp_insert->length)
{
pos = temp_insert->length;
}
node*current = &temp_insert->head;
for (int i = 0; i < pos; i++)
{
current = current->next;
}
input->next = current->next;
current->next = input;
temp_insert->length++;
printf("歌曲插入成功!!!\n\n");
}
node* find_list(common_list*old, int pos)
{
common_list*temp_find = old;
if (temp_find == nullptr)
{
printf("传入空间错误!!!\n\n");
return nullptr;
}
else if (pos < 0 || pos>=temp_find->length)
{
printf("该位置处无歌曲!!!\n\n");
return nullptr;
}
node* current = temp_find->head.next;
for (int i = 0; i < pos; i++)
{
current = current->next;
}
printf("找到歌曲啦!!!\n\n");
return current;
}
void delete_list(common_list**old, int pos)
{
common_list*temp_del = *old;
if (temp_del == nullptr)
{
printf("传入空间错误!!!\n\n");
return ;
}
else if (pos < 0 || pos >= temp_del->length)
{
printf("该位置处无歌曲!!!\n\n");
return ;
}
node* current = &temp_del->head;
for (int i = 0; i < pos; i++)
{
current = current->next;
}
node*del = current->next;
current->next = del->next;
temp_del->length--;
printf("歌曲删除成功!!!\n\n");
}
void clear_list(common_list**old)
{
common_list* temp_cls = *old;
if (temp_cls == nullptr)
{
printf("传入空间错误!!!\n\n");
return;
}
free(temp_cls);
temp_cls = nullptr;
printf("歌曲已经清空!!!\n\n");
}
typedef struct User
{
node head;
char song_name[16];
int song_time;
char star[32];
}user;
int main()
{
common_list*old = creat_list();
user* get;
user u2;
strcpy_s(u2.star, "周杰伦");
strcpy_s(u2.song_name,"告白气球");
u2.song_time = 111;
insert_list(&old,(node*)&u2,0);
user u3;
strcpy_s(u3.star, "周杰伦");
strcpy_s(u3.song_name, "mojito");
u3.song_time = 222;
insert_list(&old, (node*)&u3, 0);
user u1;
strcpy_s(u1.star, "夏婉安");
strcpy_s(u1.song_name, "新年好");
u1.song_time = 333;
insert_list(&old, (node*)&u1, 0);
user u4;
strcpy_s(u4.star, "格子兮");
strcpy_s(u4.song_name, "秋殇别恋");
u4.song_time = 444;
insert_list(&old, (node*)&u4, 8);
for (int i = 0; i < old->length; i++)
{
get = (user*)find_list(old, i);
printf("你的歌曲如下:\n歌手:%s,歌曲:%s,时间长:%d\n\n",get->star,get->song_name,get->song_time);
}
delete_list(&old,0);
for (int i = 0; i < old->length; i++)
{
get = (user*)find_list(old, i);
printf("你的歌曲如下:\n歌手:%s,歌曲:%s,时间长:%d\n\n", get->star, get->song_name, get->song_time);
}
return 0;
}
模拟手机类型管理(单链表传统版)
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<stdlib.h>
typedef struct Phone
{
int price;
char brand[8];
struct Phone *next;
}phone;
phone *insert(phone *old,phone *new_)
{
if (old == NULL)
{
printf("这个是空链表,开始插入:\n");
old = new_;
new_->next = NULL;
}
else
{
printf("这个不是空链表,继续插入:\n");
while (old->next != NULL)
{
old = old->next;
}
old->next = new_;
new_->next = NULL;
}
return old;
}
void insert(phone *old,phone *new_,int pos)
{
}
void show(phone *old)
{
int i = 0;
if (old == NULL)
{
printf("链表为空......\n");
return;
}
while(old!=NULL)
{
printf("价格为:%d, 型号为:%s\n",old->price,old->brand);
old = old->next;
}
}
void search(phone* old, int price)
{
if (old == NULL)
{
printf("链表为空......\n");
return;
}
while (old !=NULL)
{
if (old->price == price)
{
printf("该手机存在:%s,价格为:%d\n",old->brand,old->price);
return;
}
old = old->next;
}
printf("未找到!!!\n");
}
phone* delete_(phone* old_, int price)
{
phone* old = old_;
phone* new_ = old_;
if (new_ == NULL)
{
printf("链表为空......\n");
return NULL;
}
if (old->price == price)
{
printf("%s 手机存在,正在删除!!!\n", old->brand);
old = old->next;
return old;
}
while (new_ !=NULL)
{
old = old->next;
if (old->price == price && old !=NULL)
{
printf("%s 手机存在,正在删除!!!\n",old->brand);
new_->next = old->next;
return old;
}
new_ = new_->next;
}
printf("手机不存在,删除失败!!!\n");
return new_;
}
int main()
{
phone *old, *input;
old = NULL;
input = NULL;
input = (phone*)malloc(sizeof(phone));
input->price = 3999;
strcpy_s(input->brand,"iQOO7");
old = insert(old,input);
show(old);
input = (phone*)malloc(sizeof(phone));
input->price = 4999;
strcpy_s(input->brand,"iQOO5");
insert(old, input);
show(old);
input = (phone*)malloc(sizeof(phone));
input->price = 5999;
strcpy_s(input->brand,"iQOO3");
insert(old, input);
show(old);
input = (phone*)malloc(sizeof(phone));
input->price = 6999;
strcpy_s(input->brand, "iQOO");
insert(old, input);
show(old);
search(old,5999);
search(old, 3999);
search(old, 599);
printf("删除前:\n");
show(old);
delete_(old,5999);
show(old);
old = delete_(old, 3999);
show(old);
delete_(old, 6999);
show(old);
old = delete_(old, 4999);
show(old);
return 0;
}
运行结果:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/4546b2a32b671fce468c412a26c963e5.png)
模拟年龄管理(顺序存储,进阶版)
地址计算的方法
- 存储器中的每个存储单元有自己的编号,称为地址
- 假设每个数据元素占用c个单元,则第i和i+1的位置关系是:loc(i+1)=loc(i)+c。
#include<iostream>
typedef struct Song
{
int capacity;
int length;
int *node;
}song;
song* list_creat(int capacity)
{
song* old = NULL;
old = (song*)malloc(sizeof(song));
old->node = (int*)malloc(sizeof(int)*capacity);
old->length = 0;
old->capacity = capacity;
return old;
}
void insert(void *old_, void* input, int pos)
{
song* old = NULL;
if (old_ == NULL || input ==NULL || pos<0)
{
printf("输入错误!!!\n");
return;
}
old = (song*)old_;
if (old->length >= old->capacity)
{
printf("链表满了!!!\n");
return;
}
else if (pos>old->length)
{
pos = old->length;
}
for (int i = pos; i < old->length; i++)
{
old->node[pos + 1] = old->node[pos];
}
old->node[pos] = (int)input;
old->length++;
}
void* list_get(song* old, int pos)
{
if (old == NULL || pos<0)
{
printf("链表错误!!!\n");
return NULL;
}
return (void*)old->node[pos];
}
void* delete_(song* old, int pos)
{
if (old == NULL )
{
printf("链表错误!!!\n");
return NULL;
}
else if (pos<0 || pos>=old->length)
{
printf("删除位置错误!!!\n");
return NULL;
}
void* temp = (void*)old->node[pos];
for (int i = pos; i < old->length; i++)
{
old->node[i] = old->node[i + 1];
}
old->length--;
return temp;
}
int get_length(song*old)
{
if (old == NULL)
{
printf("链表错误!!!\n");
return NULL;
}
return (old->length)>=0? old->length:0;
}
void clear_list(song*old)
{
old->capacity = 0;
old->length = 0;
free( old);
old = NULL;
printf("链表已经清空!!!\n");
}
struct Star
{
int age;
}star1,star2,star3,star4;
struct Star1
{
int age;
}star_1, star_2, star_3, star_4;
int main()
{
song* s = NULL;
s = list_creat(8);
star1.age = 11;
star2.age = 21;
star3.age = 31;
star4.age = 41;
insert(s,(void*)&star1,0);
insert(s, (void*)&star2, 1);
insert(s, (void*)&star3, 2);
insert(s, (void*)&star4, 3);
star_1.age = 1;
star_2.age = 2;
star_3.age = 3;
star_4.age = 4;
insert(s, (void*)&star_1, 4);
insert(s, (void*)&star_2, 5);
insert(s, (void*)&star_3, 6);
insert(s, (void*)&star_4, 7);
int len = get_length(s);
for (int i = 0; i < len; i++)
{
printf("第【%d】个元素是:%d\n", i, *(int *)list_get(s, i));
}
printf("删除后:\n");
delete_(s,0);
delete_(s, 2);
delete_(s, 4);
delete_(s, 6);
len = get_length(s);
for (int i = 0; i < len; i++)
{
printf("第【%d】个元素是:%d\n",i,*(int *)list_get(s,i));
}
clear_list(s);
printf("链表的长度是:%d\n",get_length(s));
return 0;
}
运行结果:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/389efff1404efd35e56e01121fd9a2c8.png)
总结
顺序结构:
单链表:
- 线性表频繁插入和删除时使用,表中的元素变化较大时使用,因为这样不需要考虑存储空间大小的问题。