前言
链表在组织大量数据时候效率非常高,但是操作都是使用指针进行操作,比较容易出错。因此,掌握链表的操作很重要。
测试例子及说明
下面的例子主要实现链表节点的插入、删除链表节点、追加节点到链表、遍历链表节点。
#include <stdio.h>
#include <stdlib.h>
//定义链表节点
struct node {
int data;
struct node *next;
};
//全局变量。分别表示头结点和尾节点
struct node* head;
struct node* tail;
//初始化链表头结点和尾节点
void init(){
head = (struct node*)malloc(sizeof(struct node));
if(!head) return -1;
head->next = NULL;
tail = head;
}
//获取链表的长度
int length(){
struct node *p;
int cnt = 0;
for(p = head;p!=NULL;p = p->next)
cnt++;
return cnt;
}
//追加节点到链表
void append(int item){
struct node* p;
p = (struct node *)malloc(sizeof(struct node));
if(!p) return -1;
p ->data = item;
p ->next = NULL;
tail->next = p;
tail = p;
}
//插入节点item 到i位置
int insert(int i,int item){
struct node *q ,*ltemp;
int j=0;
ltemp = (struct node*)malloc(sizeof(struct node));
if(!ltemp) exit(-1);
q = head;
j=1;
while((q!=NULL) && (j<i)){
q = q->next;
j++;
}
if((!q) || (j>i)) exit(-1);
ltemp ->next = q ->next;
q ->next = ltemp;
if(tail == q) tail = ltemp;
return 0;
}
//删除i位置的节点
int del(int i){
struct node *p, *q;
int temp;
q = head;
p = head->next;
int j=1;
while((p!=NULL) && (i>j) ){
q = p;
p = p->next;
printf("element %d \n",p->data);
j++;
}
if(!p ) return -1;
temp = p->data;
q->next = p->next;
if(tail == p) tail = q;
free(p);
return temp;
}
//遍历链表
void traversal(){
struct node *p;
printf("list is : ");
for(p = head->next;p!=NULL;p=p->next){
printf("%d ",p->data );
}
printf("\n");
}
//链表反转
void converse(struct node **head){
if((*head) ==NULL || (*head)->next==NULL)
return -1;
struct node* p=NULL,*q=NULL;
p = NULL;
q =( *head)->next;
struct node *r = q->next;
while( r!=NULL){
q->next = p;
p = q;
q = r ;
r = q->next;
}
//参看下图的第四步骤就会明白
q->next = p;
//把q节点赋值给头指针的next
(*head) ->next= q;
}
int main(){
init();
append(1);
append(2);
append(3);
append(4);
traversal();
converse(&head);
traversal();
return 0;
}
以上函数可能链表反转有点绕。因此我把思路画出来。下图步骤4的时候,while循环会终止,但是此时的q节点是孤立的还没有链接到q指向的链中。因此,在while循环外加上q-next = p; 最后再把q节点的地址赋给head节点。这样整个链都反转过来了。
链表操作注意事项总结
1)插入节点和删除节点需要保存前置节点的指针。