1.链表定义
链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。
链表里的的每节"⻋厢"都是独⽴申请下来的空间,我们称之为“结点/节点”。
节点的组成主要有两个部分:(数据域)当前节点要保存的数据和(指针域)保存下⼀个节点的地址(指针变量)。
链表中每个节点都是独⽴申请的(即需要插⼊数据时才去申请⼀块节点的空间),我们需要通过指针 变量来保存下⼀个节点位置才能从当前节点找到下⼀个节点。
链表分为:单链表、双向链表、循环链表。
2.功能实现
单链表定义
//定义结点的结构体 typedf struct LNode{ //定义单链表结点类型 ElemType data ; //每个结点存放一个数据元素 struct LNode *next; //指针指向下一个结点 }LNode; //定义链表的结构体 typedef struct LinkList{ struct ListNode* head; //定义头结点 int size; //定义链表大小 }LinkList;
单链表初始化和销毁
void LinkListCreat(LinkList* list){ list.head=NULL; list.size=0; }
void LinkListDestory(LinkList* list){ while(list.head){ ListNode* temp=list->head; //将链表头储存在临时变量中 list->head= list->haed->next; //改变当前头结点 使其成为后继 free(temp); }//遍历完即销毁完成 list->size=0; }
单链表查询
(定义新指针p,H结构体的指针域赋值给p,判断不为空且数据域不是目标,后移,返回值)
int Get_LinkList(LinkList H, ElemType key) { LNode* p = H->next; int pos = 1; while (p != NULL && p->data != key) { p = p->next; pos++; } if (p == NULL) { return 0; // 未找到 } else { return pos; // 返回位置 } }
单链表插入
(和结构体关联 判断合法即后移,遍历到插入位置的前一个元素, 为新元素申请空间 赋值 p的next给新元素next 新元素赋值给p的next)
Status ListInsert(LinkList &H, int i, ElemType e) { LNode* p = H; int j = 0; while (p != NULL && j < i - 1) { p = p->next; j++; } if (p == NULL || j > i - 1) { return ERROR; // 插入位置不合法 } LNode* newNode = (LNode*)malloc(sizeof(LNode)); newNode->data = e; newNode->next = p->next; p->next = newNode; return OK; }
一定要先把原本结点的指针域赋值给新元素,否则后续元素可能会丢失
若插入位置是0,则直接把生成的节点的后续节点,设置为当前链表的头结点,并把生成的节点设置为新链表头
if(i==0){ newNode->data=list->head; list->head=newNode; }
最后更新链表大小,即对链表的长度进行+1操作
单链表删除
(和结构体关联 判断合法即后移,遍历到删除位置的前一个位置, 创建新指针 p的next 赋值给q q的next再给p的next(把前一个结点的后继结点设置为后继的后继) 释放q)
Status ListDelete(LinkList &H, int i) { LNode* p = H; int j = 0; while (p != NULL && j < i - 1) { p = p->next; j++; } if (p == NULL || p->next == NULL || j > i - 1) { return ERROR; // 删除位置不合法 } LNode* q = p->next; p->next = q->next; free(q); return OK; }
若i=0,头结点的next赋值给新指针next,释放头结点,把next再赋值给新的头结点
if(i==0){ ListNode* next=list->head->next; free(list->head); list->head=next; }
最后更新链表的大小,即长度-1操作
3.链表应用
3.1数列计算
给n个数求和
#include<stdio.h>
#include<stdlio.h>
int main(){
int n=0;
while(scanf("%d",&n)!=EOF){
if(n==0){
break;
}
LinkList l; //定义链表对象
LinkListCreat (&l);
for(int i=0;i<n;++i){
int x;
scanf("%d",&x);
ListInsert(&l,i,x);//输入的数插入链表尾部
}
int sum=0;
for(int i=0;i<n;++i){
sum+=LinkListGet(&l,i)->data;
}
printf("%d\n",sum);
LinkListDestroy(&l);//不销毁会导致内存泄漏
}
return 0;
}
3.2超级楼梯
有一楼梯一个m层,没词只能跨1/2级,要走上m级,一共有几种走法。
input:先n,表示测试案例个数,再n行数据,每行包含一个整数m
用斐波那契数列表示即可。
4.代码实现
#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 p = paraHeader->next;
while (p != NULL) {
printf("%c", p->data);
p = p->next;
}// Of while
printf("\r\n");
}// 打印链表
/**
* 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;
// Step 1. Construct a new node.
q = (NodePtr)malloc(sizeof(LNode));//定义一个新的结点
q->data = paraChar;
q->next = NULL;
// Step 2. Search to the tail.
p = paraHeader;
while (p->next != NULL) {
p = p->next;
}// Of while
// Step 3. Now add/link.
p->next = q;
}// 在链表的结尾添加新的节点
/**
* Insert an element to the given position.
* @param paraHeader The header of the list.
* @param paraChar The given char.
* @param paraPosition The given position.
*/
void insertElement(NodePtr paraHeader, char paraChar, int paraPosition){
NodePtr p, q;
// Step 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;
}// Of if
} // Of for i
// Step 2. Construct a new node.
q = (NodePtr)malloc(sizeof(LNode));
q->data = paraChar;
// Step 3. Now link.
printf("linking\r\n");
q->next = p->next;//将原来的节点的next的值赋给现在节点的next
p->next = q;//连接新的节点
}// Of insertElement
/**
* 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;
}// Of while
if (p->next == NULL) {
printf("Cannot delete %c\r\n", paraChar);
return;
}// Of if
q = p->next;
p->next = p->next->next;
free(q);
}// Of deleteElement
/**
* Unit test.
*/
void appendInsertDeleteTest(){
// Step 1. Initialize an empty list.
LinkList tempList = initLinkList();
printList(tempList);
// Step 2. Add some characters.
appendElement(tempList, 'H');
appendElement(tempList, 'e');
appendElement(tempList, 'l');
appendElement(tempList, 'l');
appendElement(tempList, 'o');
appendElement(tempList, '!');
printList(tempList);
// Step 3. Delete some characters (the first occurrence).
deleteElement(tempList, 'e');
deleteElement(tempList, 'a');
deleteElement(tempList, 'o');
printList(tempList);
// Step 4. Insert to a given position.
insertElement(tempList, 'o', 1);
printList(tempList);
}// Of appendInsertDeleteTest
/**
* 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
运行结构