本周结束了c高级的学习,进入学习数据结构的阶段。为了巩固对于链表思维的培养,故总结单链表的一些基本功能。
1.尾插法创建链表;
2.头插法创建链表;
3.通过节点序号查找链表;
4.通过节点序号插入数值进入链表;
5.通过节点序号删除链表;
6.释放链表;
7.链表排序;
1.尾插法创建链表;
创建头指针head和尾指针tail;新指针pnew;
1.1)若插入的是第一个节点,则将头指针和尾指针都接收新指针pnew的值;
1.2)若插入的不是第一个节点,头指针不动,一直移动尾指针。tail->next 接收pnew的值,并将tail接收pnew的值;
struct node *create_list_by_tail()
{
struct node *head = NULL; //头指针
struct node *pnew = NULL; //申请新的节点
struct node *tail = NULL; //保存最后一个节点的地址
int x;
scanf("%d", &x);
while(getchar()!='\n');
while(x)
{
//1、创建新的节点
pnew = (struct node*)malloc(sizeof(struct node));
if(NULL == pnew)
{
printf("malloc error, %s,%d\n", __FILE__, __LINE__);
exit(-1);
}
pnew->data = x;
pnew->next = NULL;
//2、加入链表
if(head == NULL)
{
head = pnew;
tail = pnew;
}
else
{
tail->next = pnew;
tail = pnew;
}
scanf("%d", &x);
while(getchar()!='\n');
}
return head;
}
2.头插法创建链表;
创建新链,头指针为pnew,原来的链表头指针为head;
2.1)若是空链表,则将head直接接收pnew的值即可;
2.2)若是非空链表,则先将新链表的尾巴接收head的值(pnew->next = head),再将head前移至pnew的位置(head = pnew)。
另:空链表的pnew->next和head都是NULL,所以头插法可以直接使用2.2。
struct node *create_list_by_head()
{
struct node *head = NULL, *pnew = NULL;
int x;
scanf("%d", &x);
while(getchar()!='\n');
while(x)
{
//1、创建新的节点,并赋值
pnew = (struct node*)malloc(sizeof(struct node));
if(NULL == pnew)
{
printf("malloc error, %s, %d\n", __FILE__,__LINE__);
exit(-1);
}
pnew->data = x;
pnew->next = NULL;
//2、加入链表
pnew->next = head;
head = pnew;
scanf("%d", &x);
while(getchar()!='\n');
}
return head;
}
3.通过节点序号查找链表;
节点序号index是输入的要查找的节点序号,只要做index-1遍遍历,即可找到要查找的节点。
执行遍历之前需要对index做检查。若index<1或者index>链表长度,都是查找不到的,要给予反馈。
struct node* list_search_by_index(struct node *head, int index)
{
//入参检查
if(NULL == head)
{
return NULL;
}
int len = list_len(head);
if(index < 1 || index>len)
{
printf("param error!%s, %d\n", __FILE__,__LINE__ );
return NULL;
}
//若正确,流程
struct node *p = head;
for(int i=1; i<index; i++ )
{
p = p->next;
}
return p;
}
4.通过节点序号插入数值进入链表;
4.1)如果是头插,则直接将新节点的尾巴指向原来的头节点,head头节点接收新节点的头指针(pnew);
4.2)若是中间或者尾部插入,则通过查找下标的方法(3.通过节点序号查找链表)找到需要插入的前一个节点(index-1),设为p,则新节点接收p的尾巴(pnew->next = p->next),p的尾巴接收新节点的头指针pnew(p->next = pnew),则可以实现插入。
struct node *list_insert_by_index(struct node *head, int index, int data)
{
//入参检查
int len = list_len(head);
if(index<1)
{
index = 1;
}
if(index>len+1)
{
index = len+1;
}
//若正确,流程
struct node * pnew=NULL;
pnew = create_node();
pnew->data = data;
if(1 == index)// 头插
{
pnew->next = head;
head = pnew;
}
else //中间或者尾部插入
{
struct node *psearch = NULL;
psearch = list_search_by_index(head, index-1);
pnew->next = psearch->next;
psearch->next = pnew;
}
return head;
}
5.通过节点序号删除链表;
5.1)入参检查:
5.1.1)头指针head不为NULL,即链表不为空;
5.1.2)输入的下标是否在范围内。
5.2)删除操作思路:
5.2.1)用一个临时指针,保存 要删除的节点地址;
5.2.2)将 要删除的节点,从链表上移除;
5.2.3)释放临时指针空间。
struct node*list_del_by_index(struct node *head, int index)
{
//入参检查
if(NULL == head)
{
return head;
}
int len = list_len(head);
if(index<1 || index>len)
{
return head;
}
//正确流程
//(1)保存删除节点地址
//(2)将删除节点从链表上移下来
// (3)释放空间
//
struct node *pdel = NULL ; //保存删除节点的地址
if(1 == index) //头删
{
pdel = head;
head = head->next;
}
else //中间删除 或者尾部删除
{
struct node *psearch = NULL;
psearch = list_search_by_index(head, index-1);
pdel = psearch->next;
psearch->next = pdel->next;
}
free(pdel);
return head;
}
6.释放链表;
6.1)用临时指针接收头指针的地址;
6.2)头指针做遍历;
6.3)释放临时指针;
struct node* list_free(struct node *head)
{
struct node *pdel = NULL;
while(head != NULL)
{
pdel = head;
head = head->next;
free(pdel);
}
return head;
}
7.链表排序;
7.1)从旧链表中找到最大值——假设pmax指向头指针head为最大,做遍历,遇到更大则取值,最后得到pmax存储的肯定是最大值节点;
7.2)将最大值节点从旧链表移除,得到一个单独的链表——如果头指针最大,则直接将头指针后移一位,否则找到pmax的前一个节点p(遍历直到找到pmax);将p的尾巴接收pmax的尾巴(p->next = pmax->next); 最后将pmax的尾巴指向NULL,得到一个pmax的单独链表;
7.3)将第二步的单独的链表,加入新链表——定义新链表为pnew,用头插法将每次取到的最大节点放入新链表,最后即可得到从小到大排序的新链表。
//1、从旧 链表中找到最大值
struct node* find_max_from_oldlist(struct node*head)
{
struct node *pmax = head;
struct node *p = head;
while(p != NULL)
{
if(p->data > pmax->data)
{
pmax = p;
}
p = p->next;
}
return pmax;
}
//2、将最大值从旧链表中移除
struct node* move_max_from_oldlist(struct node* head, struct node *pmax)
{
if(head == pmax)//头部移除
{
head = head->next;
}
else
{
struct node *p = head;
while(p->next != pmax) //找最大值前面的一个节点
{
p = p->next;
}
p->next = pmax->next;
}
pmax->next = NULL;
return head;
}
//3、将最大值加入新的链表
struct node* add_newlist(struct node* new_head, struct node* pmax)
{
pmax->next = new_head;
new_head = pmax;
return new_head;
}
struct node *list_sort(struct node *head)
{
struct node *new_head = NULL;
struct node *pmax = NULL;
while(head != NULL)
{
//1、从旧 链表中找到最大值
pmax = find_max_from_oldlist(head);
//2、将最大值从旧链表中移除
head = move_max_from_oldlist(head, pmax);
//3、将最大值加入新的链表
new_head = add_newlist(new_head, pmax);
}
return new_head;
}