链表:是一种链式存储的结构,它不要求逻辑上相邻的元素在物理位置上也相邻。
因此,为了表示每个数据元素ai与其后继数据元素ai+1之间的逻辑关系,对于数据元素ai来说,它不仅要存储自己的本身信息,还需要存储一个指示其直接后继的信息,这两部分组成数据元素ai的存储映像,称为结点。
结点包括两个域:存储本身信息的数据域和存储直接后继位置的指针域。
有这样n个结点链接成的链表为线性表的链式存储。一般结点的定义形式:
typedef struct Node
{
type data;
struct Node* next;
}Node,*Linklist;
一般会在第一个结点前设置一个头结点,头结点的数据域可以不存储任何信息,头结点的指针域存储指向第一个结点的指针。
L为头结点 不存储任何数据 a4为最后一个结点,其指针域为空。
所以每定义一个新的结点,不仅要对它输入数据,还要将链表的尾结点指向新结点,新结点的指针要及时置为空。
注意:链表的空间分配是由malloc(sizeof(Node))来申请的 删除结点最后也要通过free()来释放内存。
链表逆序:
void reverse(Linklist link)
{
if (link == NULL || link->next == NULL)
{
return;
}
Node* pre = link->next; //记录前一个节点,第一次为第一个结点
Node* node = pre->next; //记录当前节点 如果为NULL 说明除了头结点之外只有一个结点,不需要循环
while(node != NULL) //当前节点存在 则开始逆序
{
Node* nextnode = node->next; //记录当前节点的下一个节点 方便后续逆序操作 以免后续节点丢失
node->next = pre; //让当前节点的后继指针指向前一个节点
pre = node; //让前一个节点记录当前节点
node = nextnode; //让当前节点记录下一个节点
}
link->next->next = NULL; //当原来的第一个元素变为尾元素 尾元素的下一个元素置为NULL
link->next = pre; //pre经过循环后变成尾元素,让链表的头结点指向pre
}
用图像来解析一下 一个初始链表如下所示
第一次进入循环时,将当前结点指向前结点,如下所示
pre和node都记录原链表后继结点,供下一次循环调用
第二次进入循环时,nextnode记录后一结点
第二循环结束后
最后循环体结束后再对link的头结点和尾结点进行操作。
链表按指定个数逆序,剩下的若不够个数则按剩下个数逆序:比如链表为1 2 3 4 5 6 7 8 要按每3位逆序 即3 2 1 6 5 4 8 7
void reverseByNum(Node* prev,Node* node,int num){
if(node == NULL)
return;
Node* prevNode = node;
Node* curNode = node->next;
int count = 1;
while(curNode != NULL){
Node* nextNode = curNode->next;
curNode->next = prevNode;
prevNode = curNode;
curNode = nextNode;
count++;
if(count == num){
Node* tmp = prev->next;
prev->next->next = curNode;
prev->next = prevNode;
reverseByNum(tmp,curNode,num);
return;
}
}
prev->next->next = curNode;
prev->next = prevNode;
}
void reverses(Link link,int num){//封装一手手
Node *node = link->next;
reverseByNum(link,node,num);
}