0.链表概念
线性表的链式存储结构:线性表中数据元素(结点)在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理位置上不一定相邻。
头指针:是指向链表中第一个结点的指针
头结点:是在链表的首元结点之前附设的一个结点
首元节点:是指链表中存储第一个数据元素a1的节点
头结点的数据域(图中info)可以为空,也可以存放线性表长度,此结点不计入链表的长度值
1.创建链表
typedef struct LinkNode
{
char data;
struct LinkNode *next;
} LNode, *LinkList, *NodePtr;
2.初始化链表
LinkList initLinkList()
{
NodePtr tempHeader = (NodePtr)malloc(sizeof(LNode));
tempHeader->data = '\0';
tempHeader->next = NULL;
return tempHeader;
}
3.打印链表
void printList(NodePtr paraHeader)
{
NodePtr p = paraHeader->next ;
while(p != NULL)
{
printf("%c",p->data);
p = p->next;
}
printf("\r\n");
}
4.尾插**
void appendElementone(NodePtr paraHeader,char paraChar)
{
NodePtr p,q;
q = (NodePtr)malloc(sizeof(LNode));
q->data = paraChar;
q->next = NULL;
p = paraHeader;
while(p->next != NULL)
{
p = p->next;
}
p->next = q;
}
5.头插**
void appendElementtwo(NodePtr paraHeader,char paraChar)
{
NodePtr p,q;
q = (NodePtr)malloc(sizeof(LNode));
q->data = paraChar;
p = paraHeader;
if(p->next == NULL)
{
p->next = q;
q->next = NULL;
return;
}
q->next = p->next;
p->next = q;
}
6.在指定的位置插入元素
void insertElement(NodePtr paraHeader,char paraChar,int paraPosition)
{
NodePtr p,q;
q = (NodePtr)malloc(sizeof(LNode));
p = paraHeader;
int i;
for(i = 0;i < paraPosition;i ++)
{
p = p->next ;
if(p == NULL)
{
printf("The position %d is beyond the scope of the list.",paraPosition);
return;
}
}
q = (NodePtr)malloc(sizeof(LNode));
q->data = paraChar;
printf("linking\r\n");
q->next = p->next ;
p->next = q;
}
7.删除元素
void deleteElement(NodePtr paraHeader,char paraChar)
{
NodePtr p,q;
p = paraHeader;
while((p->next != NULL) && (p->next->data != paraChar))
{
p = p->next;
}
if(p->next == NULL)
{
printf("Cannot delete %c\r\n",paraChar);
return ;
}
q = p->next;
p->next = p->next->next;
free(q);
}
8.代码测试
void appendInsertDeleteTest(){
LinkList tempList = initLinkList();
printList(tempList);
//头插
appendElementtwo(tempList, 'H');
appendElementtwo(tempList, 'E');
appendElementtwo(tempList, 'L');
appendElementtwo(tempList, 'L');
appendElementtwo(tempList, 'O');
appendElementtwo(tempList, '!');
printList(tempList);
//尾插
appendElementone(tempList, 'H');
appendElementone(tempList, 'e');
appendElementone(tempList, 'l');
appendElementone(tempList, 'l');
appendElementone(tempList, 'o');
appendElementone(tempList, '!');
printList(tempList);
//删除
deleteElement(tempList, 'L');
deleteElement(tempList, 'a');
deleteElement(tempList, 'o');
printList(tempList);
//指定位置插入
insertElement(tempList, 'o', 1);
printList(tempList);
}
/**
* Address test: beyond the book.
*/
void basicAddressTest(){
LNode tempNode1, tempNode2;
tempNode1.data = 4;
tempNode1.next = NULL;
tempNode2.data = 6;
tempNode2.next = NULL;
printf("The first node: %d, %d, %d\r\n",
&tempNode1, &tempNode1.data, &tempNode1.next);
printf("The second node: %d, %d, %d\r\n",
&tempNode2, &tempNode2.data, &tempNode2.next);
tempNode1.next = &tempNode2;
}// Of basicAddressTest
/**
* The entrance.
*/
int main(){
appendInsertDeleteTest();
}// Of main
9.代码运行结果
10.总结
1、记住头节点
单链表的每个操作都要从头节点开始。如果函数内头节点发生了改变,比如在头节点之前插入节点,删除头节点,反转链表等,都需要更新头节点。否则会丢失链表。
2、遍历链表时要不断检测链表尾部。
3、插入和删除时,需要找到插入点或删除点之前的节点。注意要特别处理在头节点之前插入和删除头节点时,需要更新头节点。
4、快慢指针有时是利器。