单链表的定义
由于顺序表的插入删除操作需要移动大量的元素,影响了运行效率,因此引入了线性表的链式存储——单链表。单链表通过一组任意的存储单元来存储线性表中的数据元素,不需要使用地址连续的存储单元,因此它不要求在逻辑上相邻的两个元素在物理位置上也相邻。
单链表中结点的描述:
typedef struct LinkNode
{
char data;
struct LinkNode* next;
} LNode, * LinkList, * NodePtr;
初始化
通常会用头指针来标识一个单链表,头指针为NULL时表示一个空表。但是,为了操作方便,会在单链表的第一个结点之前附加一个结点,称为头结点。头结点的数据域可以不设任何信息,也可以记录表长等信息。头结点的指针域指向线性表的第一个元素结点。如下图所示:
代码实现:
LinkList initLinkList()
{
NodePtr tempHeader = (NodePtr)malloc(sizeof(LNode));
tempHeader->data = '\0';
tempHeader->next = NULL;
return tempHeader;
}
打印结点
声明一个指针pMove,从头结点指向的第一个结点开始,如果pMove不为空,那么就输出当前结点的值,并将pMove指向下一个结点,直到遍历到最后一个结点为止。
代码实现:
void printList(NodePtr paraHeader)
{
NodePtr pMove = paraHeader->next;
if (pMove == NULL) //判断链表是否为空
printf("the LinkList is Null\n");
else
{
while (pMove != NULL)
{
printf("%c", pMove->data);
pMove = pMove->next;
}
}
printf("\r\n");
}
数据的插入
尾插法
尾插法创建的单链表和输入顺序一致,因此称为正序建表。尾插法需要一个尾指针永远指向链表的尾结点。当我们需要输入据元素1时,创建新结点,把元素1放入新结点数据域;此时内存中如图:
再进行连结:
代码实现:
void appendElement(NodePtr paraHeader, char paraChar)
{
NodePtr p, q;
//1.Construct a new node.
q = CreateNewNode(paraChar);
//2.Search to the tail.
p = paraHeader;
while (p->next != NULL)
{
p = p->next;
}
//3.Now add link.
p->next = q;
}
指定位置插入
代码实现:
void insertElement(NodePtr paraHeader, char paraChar, int paraPosition)
{
NodePtr p, q;
//1.Search to the position.
p = paraHeader;
for (int i = 0; i < paraPosition; i++)
{
p = p->next;
if (p == NULL)
{
printf("The position %d is beyond the scope of the list.", paraPosition);
return;
}
}
//2.Construct a new node.
q = CreateNewNode(paraChar);
//3.Now link.
printf("linking\r\n");
q->next = p->next;
p->next = q;
}
删除操作
将单链表的第 i 个结点删除:先检查删除位置的合法性,然后从头开始遍历,找到表中的第 i-1 个结点,即被删除结点的前驱结点*p,被删除结点为*q,修改*p的指针域,将其指向*q的下一个结点,最后再释放结点*q的存储空间。
代码实现:
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);
}
完整代码
#include<stdio.h>
#include<malloc.h>
//Linked list of characters. The key is data.
typedef struct LinkNode
{
char data;
struct LinkNode* next;
} LNode, * LinkList, * NodePtr;
/*
*Initialize the list with a header;
*@return the pointer to the header.
*/
//创建头指针&&初始化
LinkList initLinkList()
{
NodePtr tempHeader = (NodePtr)malloc(sizeof(LNode));
tempHeader->data = '\0';
tempHeader->next = NULL;
return tempHeader;
}
/*
*Print the list;
*@param paraHeader the header of the list;
*/
//打印
void printList(NodePtr paraHeader)
{
NodePtr pMove = paraHeader->next;
if (pMove == NULL) //判断链表是否为空
printf("the LinkList is Null\n");
else
{
while (pMove != NULL)
{
printf("%c", pMove->data);
pMove = pMove->next;
}
}
printf("\r\n");
}
/*
*Create a new node;
*@param newNode a new node is created;
*@retuen the pointer to the newNode.
*/
//创建结点
LinkList CreateNewNode(char paraChar)
{
NodePtr newNode = (NodePtr)malloc(sizeof(LNode));
newNode->data = paraChar;
newNode->next = NULL;
return newNode;
}
/*
*Add an element to the tail;
*@param paraHeader the header of the list;
*@param paraChar the given char;
*/
//尾插
void appendElement(NodePtr paraHeader, char paraChar)
{
NodePtr p, q;
//1.Construct a new node.
q = CreateNewNode(paraChar);
//2.Search to the tail.
p = paraHeader;
while (p->next != NULL)
{
p = p->next;
}
//3.Now add link.
p->next = q;
}
/*
* Inser an element to the given position;
* @param paraHeader the header of the list;
* @param parChar the given char;
* @param paraPosition the given position.
*/
//指定位置插入
void insertElement(NodePtr paraHeader, char paraChar, int paraPosition)
{
NodePtr p, q;
//1.Search to the position.
p = paraHeader;
for (int i = 0; i < paraPosition; i++)
{
p = p->next;
if (p == NULL)
{
printf("The position %d is beyond the scope of the list.", paraPosition);
return;
}
}
//2.Construct a new node.
q = CreateNewNode(paraChar);
//3.Now link.
printf("linking\r\n");
q->next = p->next;
p->next = q;
}
/*
* Delete an element from the list;
* @param paraHeader the header of the list;
* @param paraChar the given char.
*/
//删除结点
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);
}
/*
* Unit test.
*/
void appendInsertDeleteTest()
{
//1.Initialize an empty list.
LinkList tempList = initLinkList();
printList(tempList);
//2.Add some characters.
appendElement(tempList, 'H');
appendElement(tempList, 'e');
appendElement(tempList, 'l');
appendElement(tempList, 'l');
appendElement(tempList, 'o');
appendElement(tempList, '!');
printList(tempList);
//3.Delete some characters (the first occurrence).
deleteElement(tempList, 'e');
deleteElement(tempList, 'a');
deleteElement(tempList, 'o');
printList(tempList);
//4.Insert to a given position.
insertElement(tempList, 'o', 1);
printList(tempList);
}
/*
* Address test:beyond the book.
*/
void basicAddressTest()
{
LNode tempNode1, tempNode2;
tempNode1.data = 4;
tempNode2.next = NULL;
tempNode2.data = 6;
tempNode2.next = NULL;
printf("The first node: %p, %p, %p\r\n",
&tempNode1, &tempNode1.data, &tempNode1.next);
printf("The second node: %p, %p, %p\r\n",
&tempNode2, &tempNode2.data, &tempNode2.next);
tempNode1.next = &tempNode2;
}
/*
* The entrance.
*/
int main()
{
appendInsertDeleteTest();
}
运行结果