单链表的基本操作:
单链表的初始化、创建、插入、删除
文章目录
声明
以下基本操作是对408数据结构伪代码的基本复现。当涉及到真正改变链表元素的操作时,伪代码的函数变量前需加“&”以实现解引用
一、定义单链表的数据类型
typedef struct Node{
int data;
struct Node *next;
}Node, *linkList;
二、初始化单链表
即生成一个只有头指针的头结点(即将头节点的指针指空即可)
头节点:链表第一个不带数据域的结点
首结点:链表第一个带数据域的结点
linkList init_List(linkList head){
head = (linkList)malloc(sizeof(Node));
if(!head) {
printf("内存分配失败");
exit(0);
}
head->next = NULL;
}
三、创建单链表
1、头插法
linkList hc_List(linkList L){
//初始化链表,若定义了初始化函数则可省略
// L = (linkList)malloc(sizeof(Node));
// L->next = NULL;
int val;
printf("请输入单链表的值(输入617退出创建单链表哦):\n");
while(val != 617){
scanf("%d", &val);
Node *pNew = (linkList)malloc(sizeof(Node));
pNew->data = val;
pNew->next = L->next;
L->next = pNew;
}
return L;
}
2、尾插法
思想:定义一个伪头结点,将每次新建的结点链在伪头结点的后面。在首结点创建之前,伪头结点即头结点,创建结点后,伪头结点后移
linkList rc_List(linkList L){
//初始化链表,若定义了初始化函数则可省略
// L = (linkList)malloc(sizeof(Node));
// L->next = NULL;
Node *pNew, *pTail=L;
int val;
printf("请输入单链表的值(输入617退出创建单链表哦):\n");
while(val != 617){
scanf("%d", &val);
pNew = (linkList)malloc(sizeof(Node));
pNew->data = val;
pTail->next = pNew;
pTail = pNew;
}
pTail->next = NULL;
return L;
}
四、单链表的遍历
1、顺序遍历
void trv_List(linkList L){
Node *pNode = L->next;
printf("\n单链表为:");
while (pNode){
printf("%d ", pNode->data);
pNode = pNode->next;
}
}
2、逆序遍历
void anti_trv_List(linkList L){
Node *pNode = L->next;
if(pNode->next)
anti_trv_List(pNode);
printf("%d ", pNode->data);
}
五、单链表的查找
1、按值查找
返回的是该值在链表对应的位置
int val_search_List(linkList L, int val){
int pos = 0;
Node *pNode = L->next;
while (pNode!=NULL && pNode->data!=val){
pNode = pNode->next;
pos++;
}
return pos+1;
}
2、按序号查找
返回的是该序号在链表中对应的结点
linkList index_search_List(linkList L, int pos){
int val=0;
Node *pNode = L->next;
while(pNode!=NULL && pos>0 && pos>val+1 && pos<sizeof(L)){
pNode = pNode->next;
val++;
}
return pNode;
}
六、单链表的插入
在第i个位置插入(在p结点前插入q结点)
linkList index_insert_List(linkList L, int pos, int val){
int i=0;
Node *pNode=L, *New;
if(pos<0 && pos>sizeof(L)){
printf("插入位置无效");
exit(0);
}
while (pNode && (pos-1)>i){
pNode = pNode->next;
++i;
}
New = (linkList)malloc(sizeof(Node));
New->data = val;
New->next = pNode->next;
pNode->next = New;
}
七、单链表的删除
1、删除第i个位置的值
linkList index_delete_List(linkList L, int i){
int i=0, val;
Node *pNode=L, *qNode;
if(pos<0 || pos> sizeof(L) || !pNode){
printf("删除位置不合法,删除失败");
exit(0);
}
while (pNode && pos-1>i){
pNode = pNode->next; //pNode移动到第i个结点前
++i;
}
qNode = pNode->next; //qNode指向第i个结点
pNode->next = qNode->next;
val = pNode->data;
free(qNode);
}
2、删除所有值为val的结点
思想:用pNode遍历整个单链表,用preNode指向pNode结点的前驱结点,用qNode删除结点
若pNode找到值为val的结点,用qNode指向该结点,然后pNode下移,preNode指向移动后的pNode即可
void del_val_List(linkList L, int val){
Node *preNode=L, *qNode, *pNode=L->next;
while (pNode){
if(pNode->data == val){
qNode = pNode;
pNode = pNode->next;
preNode->next = pNode;
free(qNode);
} else{
preNode = pNode;
pNode = pNode->next;
}
}
}
3、删除链表中的最小值
思想:用pNode遍历整个单链表,用preNode指向pNode结点的前驱结点,用minPre指向最小值结点的前驱,minNode指向最小值结点结点
- pNode一边扫描一边比较,一旦找到比minNode值大的结点,马上另minNode、minPre与pNode、preNode的指向相同,然后pNode、preNode下移
linkList del_min_List(linkList L){
Node *preNode=L, *pNode=preNode->next;
Node *minPre=preNode, *minNode=pNode;
while (pNode){
if(minNode->data > pNode->data){
minNode = pNode;
minPre = preNode;
}
preNode = pNode;
pNode = pNode->next;
}
minPre->next = minNode->next;
free(minNode);
return L;
}
八、原地置逆单链表
思想:断开头结点(将头结点指向置空),用nextPNode存放pNode的下一个结点(以免用头插法插入头结点后pNode指向为空)。用头插法将pNode插入头结点后将nextPNode付给pNode,每次使用头插法之前将nextPNode下移linkList reverse_List(linkList L){
Node *pNode, nextPNode;
pNode = L->next;
L->next = NULL;
while(pNode){
nextPNode = pNode->next;
pNode->next = L->next;
L->next = pNode;
pNode = nextPNode;
}
return L;
}
八、单链表的排序
直接插入排序
linkList sort_List(linkList L){
Node *qNode, *pNode=L->next, *nextPNode=pNode->next;
pNode->next = NULL;
pNode = nextPNode;
while(pNode){
nextPNode->next = pNode->next;
qNode = L;
while(qNode->next && pNode->data>qNode->data)
qNode = qNode->next;
pNode->next = nextPNode->next;
nextPNode->next = pNode;
pNode = nextPNode;
}
}
源码
待续