单链表就地排序

合集下载

单链表的逆置(头插法,就地逆转)

单链表的逆置(头插法,就地逆转)

单链表的逆置(头插法,就地逆转)1.头插法,将链表中的每个元素都插到链表头部,进⾏逆转。

void reverse1(Node*head)
{//头插法逆转单链表
Node*p,*q;
p=head->next;
head->next=NULL;
while(p)
{
q=p;
p=p->next;
q->next=head->next;
head->next=q;
}
}
2.就地逆置,将链表中的指针指向改变,最后将head指向链表最后⼀个元素(逆置后的第⼀个)。

void reverse2(Node*head)
{//就地逆转法
Node *p, *s, *t;
p = head; // p开始指向头结点的
s = p->next; // s最开始是指向第⼀个节点的
while ( s->next != null ) // 没有到最后⼀个节点就继续
{
t = s->next; // ⽤t指向s后⾯的⼀个节点
s->next = p; // 把s指向的那个节点想在转换成指向它前⾯的那个节点,这个时候就实现了逆序,⽽且是就地逆序
p = s; // p向后移动到s的位置
s = t; // s向后移动到t的位置,这时候完成了第⼀步的置序,后⾯继续重复之前的动作就OK了
}
head->next = null;
head->next = s;
}。

单链表上容易实现的排序方法

单链表上容易实现的排序方法

单链表上容易实现的排序方法嘿,朋友们!今天咱来聊聊单链表上那些容易实现的排序方法。

你想想啊,单链表就像是一串珠子,每个珠子都有它自己的位置和信息。

那怎么把这些珠子排得整整齐齐呢?咱先说冒泡排序吧!这就好像是在一群小朋友里,让矮个子一个一个地慢慢往前站,把高个子往后挤。

每次都把最大的那个“珠子”给浮到最上面去。

虽然它比较简单直接,但有时候可能会有点慢悠悠的哦!就像你着急出门,却发现钥匙找半天,是不是有点让人着急呀?再来看看插入排序。

这就像是玩扑克牌的时候整理手牌,拿到一张牌,就看看该把它插到哪里合适。

嘿,这多形象呀!它可以一点点地把链表变得有序,虽然可能步骤多了点,但效果还是不错的哟!还有选择排序呢!这就好像是在一群选手中挑出最厉害的那个,然后把其他的依次排好。

是不是挺有意思的?它也能完成排序的任务呢!那咱为啥要用这些排序方法呀?这还用问吗?就像你收拾房间,总不能让东西乱七八糟地堆着吧!把链表排好序,才能更方便我们查找和使用其中的数据呀!不然找个数据都得费半天劲,那多麻烦呀!这些排序方法各有各的特点和用处。

就像不同的工具,有的适合干这个,有的适合干那个。

我们得根据具体情况来选择合适的排序方法,可不能瞎用哦!不然可能会事倍功半呢!比如说,如果链表的数据量不是特别大,那冒泡排序或者插入排序可能就挺合适的。

但要是数据量大得吓人,那可能就得考虑更高效的方法啦!总之呢,单链表上的排序方法就像是我们生活中的各种小技巧,学会了它们,就能让我们的编程之路更加顺畅。

所以呀,大家可得好好掌握这些方法哦!可别小瞧了它们,它们能帮我们解决大问题呢!现在,你是不是对单链表上的排序方法有了更清楚的认识啦?。

单链表就地逆置算法

单链表就地逆置算法

单链表就地逆置算法摘要:1.单链表概述2.单链表就地逆置算法的思路3.单链表就地逆置算法的实现4.单链表就地逆置算法的优点与应用场景正文:一、单链表概述单链表是一种常见的数据结构,它由一系列节点组成,每个节点包含两个部分:数据域和指针域。

数据域用于存储数据,指针域则用于存储下一个节点的地址。

单链表只有一个头节点,但没有尾节点。

在单链表中,我们可以通过遍历指针域来访问整个链表中的数据。

二、单链表就地逆置算法的思路单链表就地逆置算法是一种在原地对单链表进行逆置的操作。

它的主要思路是:从链表的头节点开始,遍历整个链表,同时将当前节点的指针域指向下一个节点,然后将下一个节点的数据域与当前节点的数据域进行交换。

这样,在遍历完整个链表后,链表的头节点将变为尾节点,尾节点将变为头节点,从而实现了链表的逆置。

三、单链表就地逆置算法的实现以下是单链表就地逆置算法的实现过程:1.定义一个指向链表头节点的指针pre,初始时pre 指向头节点。

2.定义一个指向链表尾节点的指针p,初始时p 指向头节点。

3.使用while 循环,当pre 不为空时进行以下操作:a.将p 指向的节点的数据域与pre 指向的节点的数据域进行交换。

b.将pre 指向下一个节点,即pre = pre->next。

c.将p 指向下一个节点,即p = p->next。

4.循环结束后,链表的头节点即为原尾节点,尾节点即为原头节点,实现了链表的逆置。

四、单链表就地逆置算法的优点与应用场景单链表就地逆置算法的优点在于其空间复杂度为O(1),即只需要常数级别的额外空间。

此外,该算法的时间复杂度也为O(n),其中n 为链表的长度。

因此,该算法在处理较长的链表时,依然具有较高的效率。

python数据结构之单链表的逆序

python数据结构之单链表的逆序

python数据结构之单链表的逆序题⽬描述给定带头结点的单链表,将其逆序分析由于单链表与数组的不同,单链表的每个结点的地址都储存在其前驱结点的指针域中,对单链表中任⼀结点的访问只能从头结点开始遍历。

在对链表操作的时候应该注意在修改指针域的时候保存其后继结点的地址,以免丢失后继结点⽅法⼀、就地逆序⽅法介绍在遍历链表的时候,修改当前节点指针域的指向,使其指向他的前驱节点,这就需要三个指针变量保存结点指针域:当前结点、前驱结点和后继结点源代码class Node(object):"""结点"""def __init__(self,data=None):self.data = dataself.next = Nonedef reverse(head):"""链表逆序"""if head == None or head.next == None:returncur = head.next #当前节点next = cur.next #后继节点#将原来的头结点变为为节点pre = cur #前驱节点cur.next = Nonecur = nextwhile cur.next != None:next = cur.nextcur.next = prepre = curcur = next#最后⼀个进不了循环,在外⾯整cur.next = prehead.next = curdef main():#创建单链表print("逆序前的链表为:", end=" ")head = Node()for i in range(10):"""创建单链表"""node = Node(i)cur = headif head.next == None or head == None:head.next = nodeelse:while cur.next != None:cur = cur.nextcur.next = nodecur = headwhile cur.next != None:cur = cur.nextprint(cur.data, end=" ")print("\n逆序后的链表为:", end=" ")reverse(head)cur = headwhile cur.next != None:cur = cur.nextprint(cur.data, end=" ")if __name__ == '__main__':main()算法性能分析以上⽅法只需要对链表进⾏⼀次遍历,因此时间复杂度为O(N),N为链表的长度。

c语言链表排序算法

c语言链表排序算法

c语言链表排序算法在C语言中,链表的排序可以使用多种算法,如插入排序、归并排序、快速排序等。

以下是一个简单的插入排序算法的示例,用于对链表进行排序:C:#include<stdio.h>#include<stdlib.h>struct Node {int data;struct Node* next;};void insert(struct Node** head, int data) {struct Node* newNode= (struct Node*)malloc(sizeof(struct Node));newNode->data = data;newNode->next = NULL;if (*head == NULL) {*head = newNode;return;}struct Node* current = *head;while (current->next != NULL) {current = current->next;}current->next = newNode;}void sortList(struct Node** head) { struct Node* current = *head;while (current != NULL) {struct Node* next = current->next; while (next != NULL) {if (current->data > next->data) { int temp = current->data;current->data = next->data;next->data = temp;}next = next->next;}current = current->next;}}void printList(struct Node* head) { while (head != NULL) {printf("%d ", head->data);head = head->next;}}int main() {struct Node* head = NULL;insert(&head, 5);insert(&head, 2);insert(&head, 4);insert(&head, 1);insert(&head, 3);printf("Before sorting: ");printList(head);sortList(&head);printf("\nAfter sorting: ");printList(head);return0;}这个程序定义了一个链表节点结构体Node,其中包含一个整型数据data 和一个指向下一个节点的指针next。

链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)

链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)

链表排序(冒泡、选择、插⼊、快排、归并、希尔、堆排序)这篇⽂章分析⼀下链表的各种排序⽅法。

以下排序算法的正确性都可以在LeetCode的这⼀题检测。

本⽂⽤到的链表结构如下(排序算法都是传⼊链表头指针作为参数,返回排序后的头指针)struct ListNode {int val;ListNode *next;ListNode(int x) : val(x), next(NULL) {}};插⼊排序(算法中是直接交换节点,时间复杂度O(n^2),空间复杂度O(1))class Solution {public:ListNode *insertionSortList(ListNode *head) {// IMPORTANT: Please reset any member data you declared, as// the same Solution instance will be reused for each test case.if(head == NULL || head->next == NULL)return head;ListNode *p = head->next, *pstart = new ListNode(0), *pend = head;pstart->next = head; //为了操作⽅便,添加⼀个头结点while(p != NULL){ListNode *tmp = pstart->next, *pre = pstart;while(tmp != p && p->val >= tmp->val) //找到插⼊位置{tmp = tmp->next; pre = pre->next;}if(tmp == p)pend = p;else{pend->next = p->next;p->next = tmp;pre->next = p;}p = pend->next;}head = pstart->next;delete pstart;return head;}};选择排序(算法中只是交换节点的val值,时间复杂度O(n^2),空间复杂度O(1))class Solution {public:ListNode *selectSortList(ListNode *head) {// IMPORTANT: Please reset any member data you declared, as// the same Solution instance will be reused for each test case.//选择排序if(head == NULL || head->next == NULL)return head;ListNode *pstart = new ListNode(0);pstart->next = head; //为了操作⽅便,添加⼀个头结点ListNode*sortedTail = pstart;//指向已排好序的部分的尾部while(sortedTail->next != NULL){ListNode*minNode = sortedTail->next, *p = sortedTail->next->next;//寻找未排序部分的最⼩节点while(p != NULL){if(p->val < minNode->val)minNode = p;p = p->next;}swap(minNode->val, sortedTail->next->val);sortedTail = sortedTail->next;}head = pstart->next;delete pstart;return head;}};快速排序1(算法只交换节点的val值,平均时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))这⾥的partition我们参考(选取第⼀个元素作为枢纽元的版本,因为链表选择最后⼀元素需要遍历⼀遍),具体可以参考这⾥我们还需要注意的⼀点是数组的partition两个参数分别代表数组的起始位置,两边都是闭区间,这样在排序的主函数中:void quicksort(vector<int>&arr, int low, int high){if(low < high){int middle = mypartition(arr, low, high);quicksort(arr, low, middle-1);quicksort(arr, middle+1, high);}}对左边⼦数组排序时,⼦数组右边界是middle-1,如果链表也按这种两边都是闭区间的话,找到分割后枢纽元middle,找到middle-1还得再次遍历数组,因此链表的partition采⽤前闭后开的区间(这样排序主函数也需要前闭后开区间),这样就可以避免上述问题class Solution {public:ListNode *quickSortList(ListNode *head) {// IMPORTANT: Please reset any member data you declared, as// the same Solution instance will be reused for each test case.//链表快速排序if(head == NULL || head->next == NULL)return head;qsortList(head, NULL);return head;}void qsortList(ListNode*head, ListNode*tail){//链表范围是[low, high)if(head != tail && head->next != tail){ListNode* mid = partitionList(head, tail);qsortList(head, mid);qsortList(mid->next, tail);}}ListNode* partitionList(ListNode*low, ListNode*high){//链表范围是[low, high)int key = low->val;ListNode* loc = low;for(ListNode*i = low->next; i != high; i = i->next)if(i->val < key){loc = loc->next;swap(i->val, loc->val);}swap(loc->val, low->val);return loc;}};快速排序2(算法交换链表节点,平均时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))这⾥的partition,我们选取第⼀个节点作为枢纽元,然后把⼩于枢纽的节点放到⼀个链中,把不⼩于枢纽的及节点放到另⼀个链中,最后把两条链以及枢纽连接成⼀条链。

将单链表排序的两种方法

将单链表排序的两种方法

将单链表排序的两种⽅法对单链表排序,通常有两种⽅法。

(PS:考察⼀个程序员的C语⾔编程功底,通常看他是否能娴熟地操作链表就知道了。

当然,实际C编程中我们并不需要去重新实现链表,⽆论是Linux还是Solaris, 都有双向循环链表的标准实现。

)⽅法1:将每⼀个结点的内存地址保存到额外的数组中(也就是将链式存储转化为顺序存储),对数组进⾏排序,然后根据有序的数组重新构建链表。

⽅法2:直接对链表进⾏插⼊排序,但是实现起来⽐较复杂⼀些。

显然,⽅法1最为简单,因为将链式存储L先转化为顺序存储a[],对顺序存储a[]排序,就避免了较为复杂的链接指针操作。

⼀旦对顺序存储a[]排好序后,根据a[]重新构建⼀个链表易如反掌。

例如:设单链表list有3个结点,结点的内存地址分别为{0x977e018, 0x977e028,0x977e038}, 结点的数据域分别为{2, 3, 1}, 于是,可⽤图模拟⽅法1之排序过程如下:1. 单链表的定义typedef struct list_s {int data;struct list_s *next;} list_t;2. ⽅法1(对aux[]排序使⽤的算法是简单插⼊排序)1/*2 * Insert a[n] before a[m]3 * .-----------.4 * | |5 * o Input : a[m-1], a[m], a[m+1], ..., a[n-1], a[n], a[n+1] |6 * \ \ \ |7 * o Output: a[m-1], a[n], a[m], a[m+1], ..., a[n-1], a[n+1] |8 * \____________________________________/9*/10static void11 insert(list_t *a[], int m, int n)12 {13 list_t *t = a[n];14for (int i = n; i > m; i--)15 a[i] = a[i-1];16 a[m] = t;17 }19/*20 * Straight Insertion Sort (sisort in short)21 *22 * NOTES:23 * 1. a[i .. n-1] is not sorted and24 * a[0 .. i-1] is sorted25 * 2. walk a[0 .. i-1], if a[i] < a[j], insert a[i] before a[j]26*/27static void28 sisort(list_t *a[], size_t n)29 {30for (int i = 1; i < n; i++) {31for (int j = 0; j < i; j++) {32if (a[i]->data < a[j]->data) {33 insert(a, j, i);34break;35 }36 }37 }38 }3940static void41 list_sort(list_t **head)42 {43if (head == NULL || *head == NULL)44return;4546/* get total number of nodes in the single linked list */47int len = 0;48for (list_t *p = *head; p != NULL; p = p->next)49 len++;5051/* malloc aux[] */52 list_t **aux = (list_t **)malloc(sizeof (list_t *) * len);53if (aux == NULL) /* error */54return;5556/* save addr of per node to aux[] */57int k = 0;58for (list_t *p = *head; p != NULL; p = p->next)59 aux[k++] = p;6061/* sort aux[] via straight insertion sorting algorithm */62 sisort(aux, len);6364/* rebuild the single linked list by walking aux[] */65 *head = aux[0];66for (int i = 0; i < len - 1; i++)67 aux[i]->next = aux[i+1];68 aux[len-1]->next = NULL;6970free(aux);71 }3. ⽅法2实现链式插⼊排序的关键有两点:1. 在遍历单链表的过程中,从单链表上把某个结点p摘下来存⼊q,把q插⼊到已经有序的链表上,然后将p指针向后移(p = p->next);(注意:要将q断开(q->next = NULL),必须先执⾏p = p->next)2. 遍历已经有序的链表,计算出待插⼊结点p的前驱和后继指针。

单链表就地逆置算法

单链表就地逆置算法

单链表就地逆置算法单链表就地逆置算法是一种将单链表逆序排列的算法,不需要创建新的链表,而是通过修改链表的指针来实现逆置操作。

这种算法的时间复杂度为O(n),空间复杂度为O(1)。

在进行单链表就地逆置算法之前,我们需要先了解链表的基本概念和结构。

单链表是由节点组成的数据结构,每个节点包含两个部分:数据域和指针域。

数据域用来存储节点的数据,而指针域用来指向下一个节点。

链表的头节点是链表的第一个节点,尾节点的指针域指向NULL。

现在我们来定义一个单链表的数据结构:```ctypedef struct Node{int data;struct Node *next;```接下来,我们将介绍单链表就地逆置算法的具体实现步骤。

步骤一:检查链表是否为空或只有一个节点,如果是,则不需要进行逆置操作,直接返回头节点。

步骤二:定义三个指针变量,分别为prev、current和next。

```cNode *prev = NULL;Node *current = head;Node *next = NULL;```其中,prev用来指向当前节点的前一个节点,current用来指向当前节点,next用来指向当前节点的下一个节点。

步骤三:遍历链表,将每个节点的指针指向它的前一个节点。

具体操作如下:while(current != NULL){next = current->next;current->next = prev;prev = current;current = next;}```将next指向current节点的下一个节点,然后将current节点的指针指向prev,最后将prev指向current,current指向next。

步骤四:将链表的头节点指向逆置后的链表的头节点。

```chead = prev;```步骤五:返回逆置后的链表头节点。

```creturn head;```下面我们来看一下单链表就地逆置算法的完整代码实现:```cNode *reverseLinkedList(Node *head){if(head == NULL || head->next == NULL){return head;}Node *prev = NULL;Node *current = head;Node *next = NULL;while(current != NULL){next = current->next;current->next = prev;prev = current;current = next;}head = prev;return head;}```通过以上步骤,我们可以实现单链表的就地逆置算法。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

/*循环链表*/
/*普通链表,最后指向head,而直线链表next为NULL*/
#include<stdio.h>
#include<stdlib.h>
struct clist
{
int data;
struct clist *next;
};
typedef struct clist cnode;
typedef struct clist *clink;
clink creatlist(int *arrary,int len);
void printclist(clink head);/*循环链表的输出*/
int main(void)
{ //创建单链表
clink head;
clink before,p,q,t;//代替head
clink new_node;
int i,j,k,tmp,n,num,min;
printf("请输入n值:");
scanf("%d",&n);
scanf("%d",&num);
head=(clink) malloc(sizeof(cnode));
if(!head) return NULL;
head->data=num;
head->next=NULL;
before=head;
for(i=1;i<n;i++)
{
new_node=(clink)malloc(sizeof(cnode));
if(!new_node) return NULL;
scanf("%d",&num);
new_node->data=num;
new_node->next=NULL;
before->next=new_node;
before=new_node;
}
new_node->next=head;
if(head ==NULL)
{
printf("内存分配失败。

\n");
exit(1);
}
//输出单链表
printf("\nThe link data :");
printclist(head);
//进行就地排序
p=head;
j=1;
for(i=1;i<n;i++){
while(j<i){p=p->next;j++;}
min=p->data;q=p;
for(k=j;k<n;k++){
p=p->next;
if(min>p->data){tmp=min;min=p->data;p->data=tmp;t=p;}//找到当前最小元素,t 指向该位置
}
q->data=min;
j=1;
p=head;
}
//输出排序结果
printf("\nThe sort data: ");
printclist(head);
return 0;
}
void printclist(clink head)
{
clink ptr;
ptr=head;
do
{
printf("[%d]",ptr->data);
ptr=ptr->next;
}while(head!=ptr&&head!=head->next);
printf("\n");
}。

相关文档
最新文档