链表:用链式存储结构存储的线性表;
优点:插入删除不需要移动大量的数据,只需要修改指针即可;
缺点:表中的元素只能顺序存储,不能随机存取数据;
数据域:用来存储节点的值;
指针域:指向下一个节点(直接后继)的指针;
头指针:指向第一个节点的指针;
单链表的定义:
typedef struct node
{
int data; //数据域
node* next; //指针域
}slink;
单链表最基本的操作为指针后移,在某个节点的后面插入或删除节点;
单链表的建立:
算法思路:根据链表的示意图从头结点开始往后面建立新的节点,特别注意新建立的节点需要连接到上一个节点(也就是把上一个节点的指针域指向新建立的节点)。建立完成后,最后尾部节点后面不再建立新节点,是尾部节点的指针域置空(也就是代表着单链表的建立完成)。
slink* creslink(int n) //建立含有n个节点的单链表
{
slink* head, * p, * s;
int i;
p = head = (slink*)malloc(sizeof(slink)); // 建立头节点
for (i = 0; i < n; i++)
{
s = (slink*)malloc(sizeof(slink)); //建立节点
scanf("%d", &s->data); //输入数据
p->next = s; //将新节点连接到p所指的节点后面
p = s; //p指向新连接的节点
};
p->next = NULL; //尾部节点指针域置为空
return head; //返回头节点
};
求单链表长度操作:
算法思路:建立一个指针依次从头开始移动到尾部,找到单链表结束标志NULL,建立一个int 型的变量记录指针移动的次数,最后指针移动的次数就是表的长度。
int getlen(slink* head) //求带头节点 head单链表的长度
{
slink* p;
int n=0;
p = head->next; //让p指向第一个节点(头结点的直接后继)
while (p!= NULL) //判断p到没到尾部
{
p = p->next; //p指向后面的节点
n++; //n开始记录表长
};
return n;
};
取出单链表中第i个节点的数据:
算法思路:首先判断i的合理性,其次找到第i个节点,把i节点的值取出;
int getelem(slink* head, int i, elemtype* e) //取出带头节点head中第i个节点的数据,赋给e
{
int j = 1; slink* s;
if (i < 1)return 0; //判断i的合理性
s = head->next;
while (j < i && s != NULL)
{
s = s->next;
j++;
}; //找到第i个节点或者最后一个节点
if (s == NULL)return 0; //i超出单链表的长度,取出失败
*e = s->data; //找到了第i个节点并把值赋给e
return 1;
};
元素定位操作:查找单链表head中x值第一次出现的位置
算法思路:建立一个指针,从头开始依次访问每个节点的数据,直到找到x为止(表中没有x,指针移动到尾部)结束,并且用int 型的变量记录指针移动的次数,就是x第一次出现的位置。
int locate(slink* head, elemtype x) //查找单链表head中x第一次出现的位置
{
int i = 1; slink* p;
p = head->next;
while (p != NULL && p->data != x)
{
p = p->next;
i++;
}; //找到x的位置(没找到,移动到末尾)
if (p == NULL)return 0; //判断是否找到x,未找到输出0
else return i; //找到输出i
}
删除操作:删除单链表中第i个节点
算法思路:首先判断i的合理性,然后根据单链表的特点,删除一个节点时,不能使表断开,所以需要把删除节点的直接前驱和直接后继连接起来。
int delete(slink* head, int i,elemtype &h) //删除单链表head中第i个节点,把删除节点的值赋给h
{
if (i < 1)return 0; //判断i的合理性
slink* s, * p; int j = 0;
p = head;
while (j < i-1&&p->next!=NULL)
{
p = p->next;
j++;
} //找到第i个节点的直接前驱
if (p->next == NULL)return 0; //i超过表的长度
s = p->next; //找到第i个节点
p->next = s->next; //i节点的直接后继连接到i节点的直接前驱(删除语句)
h = s->data; //i节点的值赋给h
free(s); //释放i节点
return 1;
}
插入操作:在带头节点的单链表head的第i个节点之前插入一个值为x的新节点
算法思路:首先判断i的合理性,其次创建x节点,创建指针p,其中q指向x,在单链表中找到第i-1个节点(i节点的直接前驱)由指针p指向,在(i节点的直接前驱)节点后插入新节点x,同时注意新节点与前后节点的连接。
根据图可以得到插入语句为:
q->next=p->next;
p->next=q;
int insert(slink* head, int i, elemtype x) //在单链表head第i个节点前插入x节点
{
slink* p, * q;
int j=1;
p = head->next;
if (i < 1)return 0; //判断i的合理性
while (j < i - 1 && p != NULL)
{
p = p->next;
j++;
}; //找到第i-1个节点(i的直接前驱)
if (p->next == NULL)return 0; //i超过表长,插入失败
q = (sink*)malloc(sizeof(slink)); //创建q节点
q->data = x; //x赋值给q节点数据域
q->next = p->next; //把i节点连接到新节点(新节点成为i节点的直接前驱)
p->next = q; //把q节点连接到i-1节点(原i节点的直接前驱)
return 1;
}
输出操作:把单链表中的数据全部输出
算法思路:建立指针从头一次移动到尾部,打印指针每次移动后指向节点的数据域,直到遇到链表结束标志NULL结束移动;
void list (slink* head)
{
slink* p;
p = p->next;
while (p != NULL)
{
printf("%4d ", p->data);
p = head->next
};
}
头插法建立单链表:每次插入节点都在头节点之后
算法思路:使指针p总是指向头结点,s指向新节点,把新建立的s节点连接到怕节点后;
slink* headcre(int d) //头插法建立带头节点表长为d的单链表
{
slink*head, * p, * s; int i=0,c;
p =head = (slink*)malloc(sizeof(slink)); //建立头结点
p->next = NULL; //头结点置空
scanf("%d", &c); //输入数据
while (i
s = (slink*)malloc(sizeof(slink)); //建立新节点
s->data = c; //新节点数据域赋值
s->next = p->next; //p节点(头结点)后的节点(头结点的直接后继)连接到s节点后
p->next = s; //p节点指向新节点s(s成为p(头结点)的直接后继)
scanf("%d", &c);
i++;
}
return head; //返回单链表的头指针
}
总结:单链表总体不难,理解每一个操作的原理才能更加方便我们后门的使用以及对知识的理解。
我是初学者小志,希望能够帮到你们。



