一、链表
1、带头指针的链表
上周学习malloc函数申请的空间一般为连续的,这种方式一般会产生很多碎片空间,他的查找效率较高,但插入和删除操作很慢;
为了尽可能的利用这些碎片空间,同时学习一种插入和删除都很便利的存储方式,开始学习链表相关知识;
使用方法:
1 #include <stdio.h>
2
3 struct node
4 {
5 int data;//数据域
6 struct node *next;//指针域,保存下一个节点的地址
7 };
8
9 int main()
10 {
11 struct node* head=NULL,*pnew=NULL;
12 struct node *tail=NULL;//指向最后一个节点的地址
13
14 pnew->data=1001;
15 pnew->next=NULL;
16
17 if(head==NULL)
18 {
19 head=pnew;
20 tail=pnew;
21 }else
22 {
23 tail->next=pnew;//前一个节点的指针域指向后一个节点
24 tail=pnew;//最后一个节点的地址tail保存
25 }
26
27 printf("%d\t%p\n",p->data,p->next);
28
29 return 0;
30 }
尾插法,插入链表,要调用时,知道头指针即可遍历所有链表;
头插法为:
pnew->next=head;
head=pnew;
对链表进行相关操作:
1、释放链表
void free_room(STU** head)
{
STU* p=NULL;
while(*head!=NULL)
{
p=*head;
*head=(*head)->next;
free(p);
}
return;
}
2、排序操作
思路:从链表找出最大值,然后通过头插法加入新的链表;
分成三步:
a、从旧链表中找出最大值
b、将最大值从旧链表中移下来
c、通过头插法将移下来的节点,通过头插法形成新的链表
//1、从旧链表中找出最大值
struct node* find_max_from_oldlist(struct node *head)
{
struct node *p = head, *pmax = head;
while(p != NULL)
{
if(p->data > pmax->data)
{
pmax = p;
}
p = p->next;
}
return pmax;
}
//2、将最大值从旧链表中移下来
struct node* remove_max_from_oldlist(struct node *head, struct node *pmax)
{
if(head == pmax) //头部移除
{
head = head->next;
}
else //其他位置移除
{
struct node *p = head;
while(p->next != pmax)
{
p = p->next;
}
p->next = pmax->next;
}
return head;
}
//3、将移下来的最大值通过头插法加入新的链表
struct node* add_newlist(struct node* new_head, struct node *pmax)
{
pmax->next = new_head;
new_head = pmax;
return new_head;
}
//链表的排序操作
struct node* list_sort(struct node *head)
{
struct node *new_head = NULL;
struct node *pmax = NULL;
while(head!=NULL)
{
//1、从旧链表中找出最大值
pmax = find_max_from_oldlist(head);
//2、将最大值从旧链表中移下来
head = remove_max_from_oldlist(head, pmax);
//3、将移下来的最大值通过头插法加入新的链表
new_head = add_newlist(new_head, pmax);
}
return new_head;
}
二、快速排序算法的实现
本周学习了多种排序算法,但大多时间复杂度均为n的平方,耗时较长,快速排序算法的时间复杂度为nlog n相对较快,且理解较难,所以特此记录,并写下代码
1 #include <stdio.h>
2
3 /*
4 *函数功能:让第一个函数为基准值,前后进行排序,小的放左边,大的放右边
5 *然后找出基准值位置
6 *
7 *传递参数:数组a的起始地址,起始查找地址,结尾查找地址
8 *
9 *返回值:返回基准值的地址下标
10 *
11 *其他说明:先比较high与基准值,大则自减,小则让low的值为high,然后
12 *同理操作i
13 */
14 int find_adr(int a[],int low,int high)
15 {
16 int key=a[low];
17 while(low<high)
18 {
19 while(low<high&&a[high]>=key)
20 {
21 high--;
22 }
23
24 a[low]=a[high];
25
26 while(low<high&&a[low]<=key)
27 {
28 low++;
29 }
30
31 a[high]=a[low];
32 }
33
34 a[low]=key;
35
36 return low;
37 }
38
39 /*
40 *函数功能:快速排序功能主体,通过递归实现
41 *
42 *传递参数:数组a,起始地址,结尾地址
43 *
44 *返回值:无
45 *
46 *其他说明:函数出口为:low=high,然后调用find函数粗排序,同时递归调用
47 *两边进行查找,出口均为low=high,最后完成函数功能
48 */
49 void quick_sort(int a[],int low,int high)
50 {
51 if(low<high)
52 {
53 int ret=find_adr(a,low,high);
54 quick_sort(a,low,ret-1);
55 quick_sort(a,ret+1,high);
56 }
57 }
58
59 //O(n)=n logn时间复杂度
60 int main()
61 {
62 int a[5]={5,9,2,7,1};
63
64 quick_sort(a,0,4);
65
66 for(int i=0;i<5;i++)
67 {
68 printf("%d\n",a[i]);
69 }
70
71 return 0;
72 }
这种理解相对较为复杂,且在链表操作时可能会出现越界的情况,在通过学习一些更简便的思想后,对相关链表的快速排序操作进行如下理解:
/*
*函数功能:快速排序学号
*
*传递函数:链表第一个元素地址与最后一个元素地址
*
*返回值:无
*
*其他说明:定义两个指针i,j均在第二个位置,比基准值小的放到i左边,大的放到i与j之间
*遍历j,进行比较,最后将i的前一个与基准值对调;然后递归该函数
*/
void quick_sort_num(STU* pbegin,STU* pend)
{
if(pbegin!=NULL&&pbegin->next!=NULL&&pbegin!=pend)
{
STU* i=pbegin->next;
STU* i_pre=pbegin;
STU* j=pbegin->next;
int key=pbegin->num;
while(j!=NULL)
{
if(j->num<key)
{
swap_element(i,j);
i_pre=i;
i=i->next;
}
j=j->next;
}
swap_element(pbegin,i_pre);
quick_sort_num(pbegin,i_pre);
quick_sort_num(i,pend);
}
return;
}