今天开始敲一个通讯录。。。看到要求之后脑子里只\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a
\n\n\n\n\n\n好在纠结了很长时间终于还是知道从哪儿开始了。虽然感觉这几天的学习效率还可以,但遇到题目还是\a\a\a\a。。。代码练习应该还是太少,各个部分的用法也应该还是掌握不到位。下面是头指针链表:
//头指针
#include <stdio.h>
#include <stdlib.h>
#define FALSE 0
#define TRUE 1
typedef int linkdata;
typedef struct _node
{
linkdata data;
struct _node *next;
}Node;
void Display (Node *h) //只是显示head指向的链表,不需要对head进行操作,所以没必要传入
{ //head的地址
if (h == NULL)
return ;
int i;
int count = 0;
while(h)
{
if (count++ % 4 == 0)
printf("\n");
printf("%8d",h ->data);
h = h->next;
}
printf ("\n");
}
int Insert_head(Node **h, linkdata data) //需要改变head的值,所以传入head的地址
{
if (h == NULL)
return FALSE;
Node* node = (Node *)malloc(sizeof (Node) / sizeof (char));
if (node == NULL)
return FALSE;
node ->data = data;
node ->next = *h;
*h = node;
return TRUE;
}
int Insert_last(Node **h, linkdata data) //需要改变head的值,所以传入head的地址
{
if (h == NULL)
return FALSE;
Node* node = (Node *)malloc(sizeof (Node) / sizeof (char));
if (node == NULL)
return FALSE;
node ->data = data;
node ->next = NULL;
Node *tmp = *h;
if (*h == NULL)
{
*h = node;
}
else
{
while (tmp ->next)
{
tmp = tmp ->next;
}
tmp ->next = node;
}
return TRUE;
}
int Insert_pos(Node **h, int pos, linkdata data)
{
if (h == NULL || pos < 1)
return FALSE;
Node* node = (Node *)malloc(sizeof (Node) / sizeof (char));
if (node == NULL)
return FALSE;
node ->data = data;
if (*h == NULL) // 考虑空表
{
if (pos != 1)
{
printf ("当前表为空,插入错误\n");
free (node);
return FALSE;
} //空表插在第一个是可以的
node ->next = NULL;
*h = node;
}
else
{
if (pos == 1) //非空表对第一个操作需要改变头指针的指向
{
node ->next = *h;
*h = node;
}
else
{
Node *tmp = *h;
int i;
for (i = 0; i < pos - 2; i++)
{
if (tmp == NULL)
break;
tmp = tmp ->next;
}
if (tmp == NULL)
{
printf ("插入越界\n");
free(node);
return FALSE;
}
node ->next = tmp ->next;
tmp ->next = node;
}
}
return TRUE;
}
int Delete_data(Node **h, int pos)
{
if (h ==NULL || pos < 1 || *h == NULL) //空表在这儿判断
{
return FALSE;
}
Node* tmp = *h;
if (pos == 1)
{
Node *p = tmp ;
*h = tmp ->next;
free(p);
}
else
{
int i;
for (i = 0; i < pos - 2; i++)
{
if (tmp ->next == NULL)
break;
tmp = tmp->next;
}
if (tmp ->next == NULL)
{
printf ("删除越界\n");
return FALSE;
}
Node *p = tmp ->next;
tmp ->next = p ->next;
free(p);
}
return TRUE;
}
//逆序头指针表
int Reserve(Node **h)
{
if (h == NULL || *h ==NULL || (*h) ->next == NULL) //顺序不可变
return FALSE;
Node *pre = *h;
Node *cur = (*h) ->next;
Node *tmp;
while (cur)
{
tmp = cur ->next;
cur ->next = pre;
pre = cur;
cur = tmp;
}
(*h) ->next = NULL;
*h = pre;
return TRUE;
}
int main()
{
Node *head = NULL;
int i;
for (i = 0; i < 10; i++)
{
Insert_head(&head, i);
}
printf("插入后的数据为:\n");
Display(head);
/*for (i = 0; i < 10; i++)
{
Insert_last(&head, i);
}
Display(head);
*/
Insert_pos(&head, 8, 10000);
printf("选择pos插入后的数据:\n");
Display(head);
Delete_data(&head, 11);
printf ("数据:\n");
Display(head);
Reserve(&head);
printf("逆序后的数据为:\n");
Display(head);
return 0;
}
总体而言,头指针链表比上篇顺序表难了很多。先总结如下:
(1)头指针链表内存是不连续的,但每个节点都只有!!只有!!只有!!下一个节点的地址,所以断开链表之前一定要保存或者有另外的指向它,否则会造成内存泄漏。
(2)对于头指针的链表操作需要考虑的情况很多,不能遗漏任何一种情况,否则程序会出现异常,涉及到头指针的操作,请传入头指针的地址,对头指针的指向进行改变,否则会造成内存泄漏。
(3)对于for循环中的pos减1还是减2的问题请画图进行模拟,对于任意的pos的操作,我们应该循环到前一个值,因为链表保存了下一个地址,既然是对pos的操作,前继后继都是需要的,所以循环应该在pos的前一个点停下来。
(4)链表的 (->next)是个好东西,在各种判断,各种找地址的都很巧妙。
(5)逆序头指针表是需要三个指针,四步骤,从第一第二两个节点分别存值->逆序,->前一个后移,->后一个指向未逆序的节点。