单链表
单链表是什么
单链表是一种线性的链式存储结构,由多个节点组成(头结点,中间节点和尾结点),单链表的存储结构图如下:
来源于网页
单链表的节点是分散的,与数组不同,数组的存储结构是连续的,单链表的每个节点存储了本节点的数据和下一个节点的地址,只能单向的查找。
单链表的操作
单链表的操作主要包括,创建,增删改查,翻转,排序。
单链表的创建
单链表的创建就是创建一个头结点
这里有两种创建方式,一种是仅仅创建一个头结点,另一个是在创建有一定长度的单链表
typedef int datatype;
typedef struct node{
datatype data;
struct node * next;
}listnode, * linklist;
linklist list_creat(){
linklist H;
if((H = (linklist)malloc(sizeof(linklist))) == NULL){
puts("malloc failed!\n");
return H;
}
H->data = 0;
H->next = NULL;
return H;
}
linklist list_creat2(){
linklist H, r, p;//三个地址
datatype value;
//分配一个list
if((H = (linklist)malloc(sizeof(listnode))) == NULL){
puts("malloc failed!\n");
return H;
}
H->data = 0;
H->next = NULL;
r = H;
//建节点
while(1){
printf("input a number(-1 to exit):");
scanf("%d", &value);
if(value == -1){
break;
}
if((p = (linklist)malloc(sizeof(linklist))) == NULL){
puts("malloc failed!\n");
return H;
}
p->data = value;
p->next = NULL;
r->next = p;//将新节点的地址赋给
r = p;//写指针移动
}
return H;
}
单链表的增删改查
单链表的增,可以从头部插入,也可以指定位置插入。
头部插入时,只需修改头结点的next以及新节点的next进行赋值即可。
指定位置插入时,需要找到指定位置的上一个节点(单链表的特点,单向查找所致),然后修改上一个节点以及指定位置节点的next即可。
int list_head_insert(linklist H, datatype value){
linklist p;
if((p = (linklist)malloc(sizeof(linklist))) == NULL){
printf("malloc failed!\n");
return -1;
}
p->data = value;
p->next = H->next;
H->next = p;
}
int list_insert(linklist H, datatype value, int pos){
linklist p, q;
if(pos == 0){
p = H;
}
else{
p = list_get(H, pos-1);
}
if(p == NULL){
printf("para is invalid\n");
}
else{
if((q = (linklist)malloc(sizeof(listnode))) == NULL){
printf("malloc failed\n");
return -1;
}
q->data = value;
q->next = p->next;
p->next = q;
return 0;
}
}
单链表的删,可以指定位置删除或者是按值删除
指定位置删除,对于中间节点来说找到指定位置的上一个节点,再将指定位置的上一个节点和下一个节点连接(修改next)就行了。然而单链表里有个特殊的情况,头结点没有上一个节点。
int list_delete(linklist H, int pos){
linklist p, q;
if(pos == 0){
p = H;
}
else{
p = list_get(H, pos - 1);
}
if(p == NULL || p->next == NULL){
printf("para is invalid\n");
return -1;
}
else{
q = p->next;
p->next = q->next;
free(q);
q = NULL;
return 0;
}
}
int list_delete_value(linklist H, datatype val){
linklist p = H, q;
if(p->next == NULL){
printf("linklist is NULL\n");
return -1;
}
if(list_locate(p, val) == NULL){
printf("linklist no val\n");
return -1;
}
if(p->next->data == val){
p->next = NULL;
return 0;
}
while(p->next->data != val){
p = p->next;
}
q = p->next;
p->next = q->next;
free(q);
return 0;
}
单链表的改只需找到节点,再修改就行了。
void list_change(linklist H, datatype val_b, datatype val_a){
linklist p;
p = list_locate(H, val_b);
p->data = val_a;
}
单链表的查,可以有按位置查,按值查
linklist list_get(linklist H, int pos){
linklist p = H;
int i = -1;
if(pos < 0){
puts("position is invalid:<0\n");
return NULL;
}
while (p->next && i < pos){
p = p->next;
i++;
}
//pos太大或者找到pos
if(i == pos){
return p;
}
else{
puts("position is invalid:>length\n");
return NULL;
}
}
linklist list_locate(linklist H, datatype value){
linklist p = H->next;
while (p && p->data != value){
p = p->next;
}
return p;
}
单链表的翻转
单链表的翻转就是单链表的方向方向改变。先将单链表分成两部分,再从头插入
void list_reverse(linklist H){
linklist p, q;
p = H->next;
H->next = NULL;
while(p){
q = p;
p = p->next;
q->next = H->next;
H->next = q;
}
}
单链表的排序
升序排列,分成两部分,对数据部分进行查找最值,然后赋值
void list_sort(linklist H){
linklist p, q, r;
p = H->next;
H->next = NULL;
while(p){
q = p;
p = p->next;
r = H;
while (r->next && r->next->data < q->data){
r = r->next;
}
q->next = r->next;
r->next = q;
}
}
ile§{
q = p;
p = p->next;
r = H;
while (r->next && r->next->data < q->data){
r = r->next;
}
q->next = r->next;
r->next = q;
}
}