1,动态链表的创建
I 在每次生成新节点的时候使用库函数 malloc 动态分配存储空间
II 创建过程需要两个指针p1和p2:
刚开始p1和p2指向头结点,
然后p1指向新生成的结点。
p2是当前节点,p2的下一个节点指向新生成的结点p1.
p2后移到当前新生成的结点p1
创建新节点p1
III 使链表尾部指向空代表结束
参考 C语言程序设计(第五版)谭浩强著 P312~P314
代码实现:
//链表的结点的组成
struct LinkedList{
int val;
struct LinkedList *next;
};
//创建链表,并返回链表头结点的指针
struct LinkedList *createLinkedList(int vals[],int n)
{
if(sizeof(vals)<sizeof(int) || n < 0) //对输入的合法性检查
return NULL;
struct LinkedList *head,*p1,*p2; //head 是链表的头结点,在第一个结点被创建时赋值
int i = 0;
p1 = p2 = (struct LinkedList *)malloc(sizeof(struct LinkedList));//先使p1和p2指向第一个结点
p1->val = vals[i];
head = NULL;
while(i<n)
{
if(i == 0)
head = p1;
else
p2->next = p1; //如果新增一个非头结点,则插入到表尾
p2 = p1; //p2后移,指向新增的结点
i++;
if(i != n) //只有当数组中的元素还没有被添加到结点,生成一个新节点
{
p1 = (struct LinkedList *)malloc(sizeof(struct LinkedList));
p1->val = vals[i];
}
}
p2->next = NULL; //使链表的尾部指针为空
return head; //创建完链表后返回该链表的头指针
}
2,在链表的指定位置插入结点,返回插入后新链表的头结点
struct LinkedList *insertListAfter(struct LinkedList *L,int index,int num)
{
//输入的合法性检查
if(L == NULL || index < 0)
return NULL;
struct LinkedList *p,*s; //s 指向要插入的结点
int i = 0;
p = L;
while(p!=NULL && i<index-1)//找到结点要插入的位置
{
p = p->next;
i++;
}
s = (struct LinkedList *)malloc(sizeof(struct LinkedList));
s->val = num;
if(index == 0)
{
s->next = p; //在表头插入结点
return s;
}
s->next = p->next;//把待插入结点后面部分连接起来
p->next = s;//
return L;//返回链表的头结点指针
}
3,删除链表的指定结点
struct LinkedList *deleteList(struct LinkedList *L,int index,int len)
{
//输入合法性检查
if(L == NULL ||index<0 || index >len-1)
return NULL;
struct LinkedList *p,*q;
int i = 0;
p = L;
while(p && i<index - 1)//找到要删除节点的前一个节点的位置
{
p = p->next;
i++;
}
if(index == 0)
{
q = p->next;
free(p);
return q;
}
q = p->next;
p->next = p->next->next;
free(q);//释放结点
return L;
}
4,链表的反向打印有三种思路
a,先把先把链表翻转,然后从头开始打印
b,遍历链表,没遍历一个节点就存入栈中。遍历完后再从栈顶弹出节点值,这种方法需要开辟一个栈,需要额外的存储空 间。
c,利用递归,此方法不适用于较长的链表
面试的时候,采用递归法即可
void printLisrReversingly(struct LinkedList *head)
{
if(head != NULL) //输入合法性检查,防止出现输入空指针
{
if(head->next != NULL)
{
printLisrReversingly(head->next);
}
printf("node:%d\t",head->val);
}
}