链表(Linked List)
- 定义结点类型,链表的基本单元:
typedef struct _node
{
int value;
struct _node * next;
}Node;
- 定义列表类型,存放链表头结点指针和尾结点指针,表示一个链表类型:
typedef struct _list
{
Node * head;
Node * tail;
}List;
- 声明一个结点基本单元并初始化
Node * p = (Node *) malloc (sizeof(Node));
p->value = number;
p->next = null;
- 声明一个链表并初始化头尾指针
List list;
list.head = list.tail = NULL;
- 将新结点链接到list(Linked_list)上
//如果此时链表头为空,即开始添加刚申请到并初始化完成的第一个结点
if(list.head == NULL)
list.head = list.tail = p;
//否则则代表链表中已存在结点,将先前tail->next指向新申请到的p,完成链接新结点
else
{
list.tail->next = p;
list.tail = p;
}
通过以上五个步骤便已经完成了创建链表(linked_list)
关于链表的其他操作(查找、删除、清除)
- 如何查找链表中相应元素,即如何遍历
Node * p;
for(p = list.head;p;p = p->next)
{
if(p->value == number)
{
printf("Found!\n");
break;
}
}
- 删除链表指定元素,查找到删除当前位置,让前一个链接到后一个结点,注意删除头结点情况
Node *p,*q;
for(q = NULL,p = list.head;p;q = p,p = p->next)
if(number == p->value)
if(q == NULL)
{
list.head = p->next;
break;
}
else
{
q->next = p->next;
free(p);
break;
}
- 清除整个链表
Node *p,*q;
for(p = list.head;p;p = q)
{
q = p->next;
free(p);
}
以上是关于链表的常见操作(查找、删除、清除)的方法;
重点:关于封装的方法
需要注意的三点:
- 函数基于已定义的结点、链表类型
- 函数的接口采用指向链表的指针,便于修改链表
- 此处仅演示创建链表类型,传递链表指针处理的方法
优点:基于我们自己定义的List类型我们可以创建一系列的链表,并用各种函数处理单个链表,相当于有了一个链表的完整体系。
- 定义结点以及链表类型
//定义结点,链表的基本单元
typedef struct _node
{
int value;
struct _node * next;
}Node;
//定义链表类型,存放链表头结点指针和尾结点指针
typedef struct _list
{
Node * head;
Node * tail;
}List;
//声明一个链表
List list;
- 添加新结点的函数.
函数原型: void add_to_list(List * ls, int num);
void add_to_list(List * ls, int num)
{
Node * p = (Node *) malloc (sizeof(Node));
p->value = num;
p->next = null;
if(ls->head == NULL)
ls->head = ls->tail = p;
else
{
ls->tail->next = p;
ls->tail = p;
}
}
- 查找元素的函数.
函数原型: void find_in_list(List * ls, int num);
void find_in_list(List * ls, int num)
{
Node * p;
bool isfound = false;
for(p = ls->head;p;p = p->next)
if(p->value == num)
{
isfound = true;
break;
}
if(isfound)
printf("Found!\n");
else
printf("Not Found!\n");
}
- 删除指定元素的函数
函数原型: void del_a_num(List * ls, int num);
void del_a_num(List * ls, int num)
{
Node *p, *q;
for(q = NULL,p = ls->head;p;q=p, p = p->next)
if(num == p->value)
{
if(q == NULL)
{
ls->head = p->next;
break;
}else
{
q->next = p->next;
free(p);
break;
}
}
}
- 清除整个链表的函数
函数原型: void del_linked_list(List * ls);
void del_linked_list(List * ls)
{
Node *p,*q;
for(p = ls->head;p;p = q)
{
q = p->next;
free(p);
}
}
建立ADT并实现接口练习
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
//假设我们要做一个存放int类型值的一个链表,并开发建立接口
/* 第一步,建立抽象数据类型(ADT) */
//定义结点类型
typedef struct _node
{
int value;
struct _node * next;
}Node;
//定义链表类型,最终抽象出的ADT
typedef struct _list
{
Node * head;
Node * tail;
}List;
/* 第二步,抽象接口 */
void add(List * ls, int val);//添加一个新项
bool is_empty(const List * ls);//确定链表是否为空
bool is_full(const List * ls);//确定链表是否已满,遍历检查
int count(const List * ls);//确定链表项数
void show(const List * ls);//访问链表每一项,显示
void insert(List * ls, int index, int val);//链表中任意位置插入一个项
void remove(List * ls, int val);//移除链表中的一个项
bool found(const List * ls, int val);//在链表中检索一个项(不改变链表)
void change(List * ls, int index, int val);//用另一个项替换链表中的一个项
int research(const List * ls, int val);//链表中搜索一个项目,返回位置,-1表示未找到
void clear(List * ls);//清空整个链表
/* 第三步,实现接口 */
void add(List * ls, int val)
{
Node * p = (Node *) malloc (sizeof(Node));
p->value = val;
p->next = NULL;
//第一个结点
if(ls->head == NULL)
ls->head = ls->tail = p;
else //后续结点
{
ls->tail->next = p;
ls->tail = p;
}
}
bool is_empty(const List * ls)
{
bool ret = false;
if(ls->head == NULL && ls->tail == NULL)
ret = true;
return ret;
}
bool is_full(const List * ls)
{
bool ret = true;
Node * p;
for(p = ls->head;p;p = p->next)
if(&(p->value) == NULL)
{
ret = false;
break;
}
return ret;
}
int count(const List * ls)
{
int cnt = 0;
Node * p;
for(p = ls->head;p;p = p->next)
cnt++;
return cnt;
}
void show(const List * ls)
{
Node * p;
for(p = ls->head;p;p = p->next)
printf("%d ",p->value);
putchar('\n');
}
void insert(List * ls, int index, int val)
{
int i = 0;
Node * new = (Node *) malloc (sizeof(Node));
new->value = val;
Node * p, * q;
for(q = NULL, p = ls->head;p;q = p, p = p->next,i++)
{
//插在第一个
if(index == 0)
{
new->next = ls->head;
ls->head = new;
break;
//插在最后一个
}else if (index == count(ls)) {
new->next = NULL;
ls->tail->next = new;
ls->tail = new;
break;
//插在中间
}else if (index == i) {
q->next = new;
new->next = p;
break;
}
}
}
void remove(List * ls, int val)
{
Node *p, *q;
for(q = NULL, p = ls->head;p;q = p, p = p->next)
if(p->value == val)
{
//删除的是第一个
if(q == NULL)
{
ls->head = p->next;
free(p);
break;
}else
{
q->next = p->next;
free(p);
break;
}
}
}
bool found(const List * ls, int val)
{
bool ret = false;
Node * p;
for(p = ls->head;p;p = p->next)
if(p->value == val)
ret = true;
return ret;
}
void change(List * ls, int index, int val)
{
int i = 0;
Node * p;
for(p = ls->head;p;p = p->next, i++)
if(i == index)
{
p->value = val;
break;
}
}
int research(const List * ls, int val)
{
int ret = -1;
int index = 0;
Node * p;
for(p = ls->head;p;p = p->next, index++)
if(p->value == val)
{
ret = index;
break;
}
return ret;
}
void clear(List * ls)
{
Node *q, *p;
for(p = ls->head;p;p = q)
{
q = p->next;
free(p);
}
}
驱动测试以上接口
2019.12.7
修炼之路(一)
未完待续
归期不定
by lx