C语言-链表基本操作
根据动态分配内存的思路可以实现可变长度数组(主要是copy整体+1),但可变数组存在明显缺陷(尤其面临内存受限的场合),对于内存的利用率不充分。更好的思路是一小块一小块内存单独申请出来,然后将它们链接起来(linked),这样不用拷贝-节省时间,又可以充分利用内存空间角落-空间利用率高 —— 链式结构。
数组属于线性表的一种,原本是顺序存储,现在改用链式存储实现。
【补充介绍:数据结构包含的三个方面
(1)逻辑关系:线性结构(线性表,栈、队列、数组、串) 非线性结构(树结构、图/网结构)
(2)物理存储:顺序 链式 索引 散列
(3)常用运算/操作:插入、删除、更新、查找、排序
逻辑关系和存储结构可以任意搭配组合】
单向链表的增删查操作
单向链表包含的元素:
头指针head一开始指向空。
结点(数据+指向下一个的指针),最后一个结点的指针为空。
向链表插入成员:
#include <stdio.h>
#include <stdlib.h>
typedef struct _node {
int value;
struct _node *next; //此时编译器还不知道 Node
} Node;
//Node *head; //如果作为全局变量解决传值问题,只能对本程序一个链表起作用,不通用
//自己定义一个结构List来代表整个链表,将来可以不断改进结构
typedef struct _list {
Node *head;
//Node *tail;
} List;
void add(List *pList, int number); //Node **phead Node* add return head
/* *** */
int main()
{
List list;
//Node *head = NULL;
int number;
list.head = NULL; //list.tail = NUll;
do {
scanf("%d", &number);
if ( number != -1 ) {
add(&list, number);
}
} while ( number != -1 );
//
Node *p;
for ( p = list.head; p; p = p->next ) {
printf("%d\t", p->value);
}
printf("\n");
}
void add(List *pList, int number) { //Node **phead 指针的指针
//add to linked-list
Node *p = (Node*)calloc(1, sizeof(Node));
p->value = number;
p->next = NULL;
//find the last
Node *last = pList->head; //*phead
if ( last ) {
while ( last->next ) {
last = last->next;
}
//attach
last->next = p;
}
else {
pList->head = p; //the first
}
}
查询链表成员 与 删除成员:
查询全部就是遍历,查询某一个就是有条件地遍历;
删除成员 需要 先查询到 要删除的成员,然后再建立新链接( 要多记录上一个结点的指针,除非是双向链表 ),断开旧链接, 最后释放结点空间。
#include <stdio.h>
#include <stdlib.h>
typedef struct _node {
int value;
struct _node *next; //此时编译器还不知道 Node
} Node;
//Node *head; //如果作为全局变量解决传值问题,只能对本程序一个链表起作用,不通用
//自己定义一个结构List来代表整个链表,将来可以不断改进结构
typedef struct _list {
Node *head;
//Node *tail;
} List;
void add(List *pList, int number); //Node **phead Node* add return head
void print(List *pList);
int search(List *pList, int number);
void remove_Member(List *pList, int number); // 删除delete 就是先search,再建立新链接,断开旧链接,最后free p
/* *** */
int main()
{
List list;
//Node *head = NULL;
int number;
list.head = NULL; //list.tail = NUll;
do {
scanf("%d", &number);
if ( number != -1 ) {
//插入链表
add(&list, number);
}
} while ( number != -1 );
//遍历输出
print(&list);
//查询
scanf("%d", &number);
search(&list, number);
//删除成员
remove_Member(&list, number);
search(&list, number);
//清除链表
Node *p, *q;
for ( p = list.head; p; p = q ) {
q = p->next;
free(p);
}
}
void add(List *pList, int number) { //Node **phead 指针的指针
//add to linked-list
Node *p = (Node*)calloc(1, sizeof(Node));
p->value = number;
p->next = NULL;
//find the last
Node *last = pList->head; //*phead
if ( last ) {
while ( last->next ) {
last = last->next;
}
//attach
last->next = p;
}
else {
pList->head = p; //the first
}
}
void print(List *pList) {
Node *p;
for ( p = pList->head; p; p = p->next ) {
printf("%d\t", p->value);
}
printf("\n");
}
int search(List *pList, int number) {
Node *p;
int isFound = 0;
int cnt = 0;
for ( p = pList->head; p; p = p->next ) {
cnt ++;
if ( p->value == number ) {
printf("找到了!是表中第%d个。\n", cnt); //
isFound = 1;
break;
}
}
if ( !isFound ) {
printf("没找到。(%d)\n", cnt);
}
return cnt;
}
void remove_Member(List *pList, int number) {
Node *p, *q;
for ( q=NULL, p=pList->head; p; q=p, p=p->next ) { //条件是p非空
if ( p->value == number ) {
if ( q ) {
q->next = p->next; //指针出现在左边,绝对不能是NULL,需要考虑可能的边界情况
}
else {
pList->head = p->next;
}
free(p);
break;
}
}
}
这就算一个基础的单链表模板完成了。